diff test/rest_common.py @ 5606:5fc476d4e34c

Merge REST API changes
author Ralf Schlatterbeck <rsc@runtux.com>
date Wed, 30 Jan 2019 18:11:02 +0100
parents ed02a1e0aa5d
children 1c4adab65faf
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/rest_common.py	Wed Jan 30 18:11:02 2019 +0100
@@ -0,0 +1,520 @@
+import unittest
+import os
+import shutil
+import errno
+
+from roundup.cgi.exceptions import *
+from roundup import password, hyperdb
+from roundup.rest import RestfulInstance
+from roundup.backends import list_backends
+from roundup.cgi import client
+import random
+
+from .db_test_base import setupTracker
+
+NEEDS_INSTANCE = 1
+
+
+class TestCase():
+
+    backend = None
+
+    def setUp(self):
+        self.dirname = '_test_rest'
+        # set up and open a tracker
+        self.instance = setupTracker(self.dirname, self.backend)
+
+        # open the database
+        self.db = self.instance.open('admin')
+
+        # Get user id (user4 maybe). Used later to get data from db.
+        self.joeid = self.db.user.create(
+            username='joe',
+            password=password.Password('random'),
+            address='random@home.org',
+            realname='Joe Random',
+            roles='User'
+        )
+
+        self.db.commit()
+        self.db.close()
+        self.db = self.instance.open('joe')
+        # Allow joe to retire
+        p = self.db.security.addPermission(name='Retire', klass='issue')
+        self.db.security.addPermissionToRole('User', p)
+
+        self.db.tx_Source = 'web'
+
+        self.db.issue.addprop(tx_Source=hyperdb.String())
+        self.db.msg.addprop(tx_Source=hyperdb.String())
+
+        self.db.post_init()
+
+        thisdir = os.path.dirname(__file__)
+        vars = {}
+        with open(os.path.join(thisdir, "tx_Source_detector.py")) as f:
+            code = compile(f.read(), "tx_Source_detector.py", "exec")
+            exec(code, vars)
+        vars['init'](self.db)
+
+        env = {
+            'PATH_INFO': 'http://localhost/rounduptest/rest/',
+            'HTTP_HOST': 'localhost',
+            'TRACKER_NAME': 'rounduptest'
+        }
+        self.dummy_client = client.Client(self.instance, None, env, [], None)
+        self.empty_form = cgi.FieldStorage()
+
+        self.server = RestfulInstance(self.dummy_client, self.db)
+
+    def tearDown(self):
+        self.db.close()
+        try:
+            shutil.rmtree(self.dirname)
+        except OSError as error:
+            if error.errno not in (errno.ENOENT, errno.ESRCH):
+                raise
+
+    def testGet(self):
+        """
+        Retrieve all three users
+        obtain data for 'joe'
+        """
+        # Retrieve all three users.
+        results = self.server.get_collection('user', self.empty_form)
+        self.assertEqual(self.dummy_client.response_code, 200)
+        self.assertEqual(len(results['data']), 3)
+
+        # Obtain data for 'joe'.
+        results = self.server.get_element('user', self.joeid, self.empty_form)
+        results = results['data']
+        self.assertEqual(self.dummy_client.response_code, 200)
+        self.assertEqual(results['attributes']['username'], 'joe')
+        self.assertEqual(results['attributes']['realname'], 'Joe Random')
+
+        # Obtain data for 'joe'.
+        results = self.server.get_attribute(
+            'user', self.joeid, 'username', self.empty_form
+        )
+        self.assertEqual(self.dummy_client.response_code, 200)
+        self.assertEqual(results['data']['data'], 'joe')
+
+    def testFilter(self):
+        """
+        Retrieve all three users
+        obtain data for 'joe'
+        """
+        # create sample data
+        try:
+            self.db.status.create(name='open')
+        except ValueError:
+            pass
+        try:
+            self.db.status.create(name='closed')
+        except ValueError:
+            pass
+        try:
+            self.db.priority.create(name='normal')
+        except ValueError:
+            pass
+        try:
+            self.db.priority.create(name='critical')
+        except ValueError:
+            pass
+        self.db.issue.create(
+            title='foo4',
+            status=self.db.status.lookup('closed'),
+            priority=self.db.priority.lookup('critical')
+        )
+        self.db.issue.create(
+            title='foo1',
+            status=self.db.status.lookup('open'),
+            priority=self.db.priority.lookup('normal')
+        )
+        issue_open_norm = self.db.issue.create(
+            title='foo2',
+            status=self.db.status.lookup('open'),
+            priority=self.db.priority.lookup('normal')
+        )
+        issue_closed_norm = self.db.issue.create(
+            title='foo3',
+            status=self.db.status.lookup('closed'),
+            priority=self.db.priority.lookup('normal')
+        )
+        issue_closed_crit = self.db.issue.create(
+            title='foo4',
+            status=self.db.status.lookup('closed'),
+            priority=self.db.priority.lookup('critical')
+        )
+        issue_open_crit = self.db.issue.create(
+            title='foo5',
+            status=self.db.status.lookup('open'),
+            priority=self.db.priority.lookup('critical')
+        )
+        base_path = self.dummy_client.env['PATH_INFO'] + 'data/issue/'
+
+        # Retrieve all issue status=open
+        form = cgi.FieldStorage()
+        form.list = [
+            cgi.MiniFieldStorage('where_status', 'open')
+        ]
+        results = self.server.get_collection('issue', form)
+        self.assertEqual(self.dummy_client.response_code, 200)
+        self.assertIn(get_obj(base_path, issue_open_norm), results['data'])
+        self.assertIn(get_obj(base_path, issue_open_crit), results['data'])
+        self.assertNotIn(
+            get_obj(base_path, issue_closed_norm), results['data']
+        )
+
+        # Retrieve all issue status=closed and priority=critical
+        form = cgi.FieldStorage()
+        form.list = [
+            cgi.MiniFieldStorage('where_status', 'closed'),
+            cgi.MiniFieldStorage('where_priority', 'critical')
+        ]
+        results = self.server.get_collection('issue', form)
+        self.assertEqual(self.dummy_client.response_code, 200)
+        self.assertIn(get_obj(base_path, issue_closed_crit), results['data'])
+        self.assertNotIn(get_obj(base_path, issue_open_crit), results['data'])
+        self.assertNotIn(
+            get_obj(base_path, issue_closed_norm), results['data']
+        )
+
+        # Retrieve all issue status=closed and priority=normal,critical
+        form = cgi.FieldStorage()
+        form.list = [
+            cgi.MiniFieldStorage('where_status', 'closed'),
+            cgi.MiniFieldStorage('where_priority', 'normal,critical')
+        ]
+        results = self.server.get_collection('issue', form)
+        self.assertEqual(self.dummy_client.response_code, 200)
+        self.assertIn(get_obj(base_path, issue_closed_crit), results['data'])
+        self.assertIn(get_obj(base_path, issue_closed_norm), results['data'])
+        self.assertNotIn(get_obj(base_path, issue_open_crit), results['data'])
+        self.assertNotIn(get_obj(base_path, issue_open_norm), results['data'])
+
+    def testPagination(self):
+        """
+        Retrieve all three users
+        obtain data for 'joe'
+        """
+        # create sample data
+        for i in range(0, random.randint(5, 10)):
+            self.db.issue.create(title='foo' + str(i))
+
+        # Retrieving all the issues
+        results = self.server.get_collection('issue', self.empty_form)
+        self.assertEqual(self.dummy_client.response_code, 200)
+        total_length = len(results['data'])
+
+        # Pagination will be 70% of the total result
+        page_size = total_length * 70 // 100
+        page_zero_expected = page_size
+        page_one_expected = total_length - page_zero_expected
+
+        # Retrieve page 0
+        form = cgi.FieldStorage()
+        form.list = [
+            cgi.MiniFieldStorage('page_size', page_size),
+            cgi.MiniFieldStorage('page_index', 0)
+        ]
+        results = self.server.get_collection('issue', form)
+        self.assertEqual(self.dummy_client.response_code, 200)
+        self.assertEqual(len(results['data']), page_zero_expected)
+
+        # Retrieve page 1
+        form = cgi.FieldStorage()
+        form.list = [
+            cgi.MiniFieldStorage('page_size', page_size),
+            cgi.MiniFieldStorage('page_index', 1)
+        ]
+        results = self.server.get_collection('issue', form)
+        self.assertEqual(self.dummy_client.response_code, 200)
+        self.assertEqual(len(results['data']), page_one_expected)
+
+        # Retrieve page 2
+        form = cgi.FieldStorage()
+        form.list = [
+            cgi.MiniFieldStorage('page_size', page_size),
+            cgi.MiniFieldStorage('page_index', 2)
+        ]
+        results = self.server.get_collection('issue', form)
+        self.assertEqual(self.dummy_client.response_code, 200)
+        self.assertEqual(len(results['data']), 0)
+
+    def testPut(self):
+        """
+        Change joe's 'realname'
+        Check if we can't change admin's detail
+        """
+        # change Joe's realname via attribute uri
+        form = cgi.FieldStorage()
+        form.list = [
+            cgi.MiniFieldStorage('data', 'Joe Doe Doe')
+        ]
+        results = self.server.put_attribute(
+            'user', self.joeid, 'realname', form
+        )
+        results = self.server.get_attribute(
+            'user', self.joeid, 'realname', self.empty_form
+        )
+        self.assertEqual(self.dummy_client.response_code, 200)
+        self.assertEqual(results['data']['data'], 'Joe Doe Doe')
+
+        # Reset joe's 'realname'.
+        form = cgi.FieldStorage()
+        form.list = [
+            cgi.MiniFieldStorage('realname', 'Joe Doe')
+        ]
+        results = self.server.put_element('user', self.joeid, form)
+        results = self.server.get_element('user', self.joeid, self.empty_form)
+        self.assertEqual(self.dummy_client.response_code, 200)
+        self.assertEqual(results['data']['attributes']['realname'], 'Joe Doe')
+
+        # check we can't change admin's details
+        results = self.server.put_element('user', '1', form)
+        self.assertEqual(self.dummy_client.response_code, 403)
+        self.assertEqual(results['error']['status'], 403)
+
+    def testPost(self):
+        """
+        Post a new issue with title: foo
+        Verify the information of the created issue
+        """
+        form = cgi.FieldStorage()
+        form.list = [
+            cgi.MiniFieldStorage('title', 'foo')
+        ]
+        results = self.server.post_collection('issue', form)
+        self.assertEqual(self.dummy_client.response_code, 201)
+        issueid = results['data']['id']
+        results = self.server.get_element('issue', issueid, self.empty_form)
+        self.assertEqual(self.dummy_client.response_code, 200)
+        self.assertEqual(results['data']['attributes']['title'], 'foo')
+        self.assertEqual(self.db.issue.get(issueid, "tx_Source"), 'web')
+
+    def testPostFile(self):
+        """
+        Post a new file with content: hello\r\nthere
+        Verify the information of the created file
+        """
+        form = cgi.FieldStorage()
+        form.list = [
+            cgi.MiniFieldStorage('content', 'hello\r\nthere')
+        ]
+        results = self.server.post_collection('file', form)
+        self.assertEqual(self.dummy_client.response_code, 201)
+        fileid = results['data']['id']
+        results = self.server.get_element('file', fileid, self.empty_form)
+        results = results['data']
+        self.assertEqual(self.dummy_client.response_code, 200)
+        self.assertEqual(results['attributes']['content'], 'hello\r\nthere')
+
+    def testAuthDeniedPut(self):
+        """
+        Test unauthorized PUT request
+        """
+        # Wrong permissions (caught by roundup security module).
+        form = cgi.FieldStorage()
+        form.list = [
+            cgi.MiniFieldStorage('realname', 'someone')
+        ]
+        results = self.server.put_element('user', '1', form)
+        self.assertEqual(self.dummy_client.response_code, 403)
+        self.assertEqual(results['error']['status'], 403)
+
+    def testAuthDeniedPost(self):
+        """
+        Test unauthorized POST request
+        """
+        form = cgi.FieldStorage()
+        form.list = [
+            cgi.MiniFieldStorage('username', 'blah')
+        ]
+        results = self.server.post_collection('user', form)
+        self.assertEqual(self.dummy_client.response_code, 403)
+        self.assertEqual(results['error']['status'], 403)
+
+    def testAuthAllowedPut(self):
+        """
+        Test authorized PUT request
+        """
+        self.db.setCurrentUser('admin')
+        form = cgi.FieldStorage()
+        form.list = [
+            cgi.MiniFieldStorage('realname', 'someone')
+        ]
+        try:
+            self.server.put_element('user', '2', form)
+        except Unauthorised as err:
+            self.fail('raised %s' % err)
+        finally:
+            self.db.setCurrentUser('joe')
+
+    def testAuthAllowedPost(self):
+        """
+        Test authorized POST request
+        """
+        self.db.setCurrentUser('admin')
+        form = cgi.FieldStorage()
+        form.list = [
+            cgi.MiniFieldStorage('username', 'blah')
+        ]
+        try:
+            self.server.post_collection('user', form)
+        except Unauthorised as err:
+            self.fail('raised %s' % err)
+        finally:
+            self.db.setCurrentUser('joe')
+
+    def testDeleteAttributeUri(self):
+        """
+        Test Delete an attribute
+        """
+        # create a new issue with userid 1 in the nosy list
+        issue_id = self.db.issue.create(title='foo', nosy=['1'])
+
+        # remove the title and nosy
+        results = self.server.delete_attribute(
+            'issue', issue_id, 'title', self.empty_form
+        )
+        self.assertEqual(self.dummy_client.response_code, 200)
+
+        results = self.server.delete_attribute(
+            'issue', issue_id, 'nosy', self.empty_form
+        )
+        self.assertEqual(self.dummy_client.response_code, 200)
+
+        # verify the result
+        results = self.server.get_element('issue', issue_id, self.empty_form)
+        results = results['data']
+        self.assertEqual(self.dummy_client.response_code, 200)
+        self.assertEqual(len(results['attributes']['nosy']), 0)
+        self.assertListEqual(results['attributes']['nosy'], [])
+        self.assertEqual(results['attributes']['title'], None)
+
+    def testPatchAdd(self):
+        """
+        Test Patch op 'Add'
+        """
+        # create a new issue with userid 1 in the nosy list
+        issue_id = self.db.issue.create(title='foo', nosy=['1'])
+
+        # add userid 2 to the nosy list
+        form = cgi.FieldStorage()
+        form.list = [
+            cgi.MiniFieldStorage('op', 'add'),
+            cgi.MiniFieldStorage('nosy', '2')
+        ]
+        results = self.server.patch_element('issue', issue_id, form)
+        self.assertEqual(self.dummy_client.response_code, 200)
+
+        # verify the result
+        results = self.server.get_element('issue', issue_id, self.empty_form)
+        results = results['data']
+        self.assertEqual(self.dummy_client.response_code, 200)
+        self.assertEqual(len(results['attributes']['nosy']), 2)
+        self.assertListEqual(results['attributes']['nosy'], ['1', '2'])
+
+    def testPatchReplace(self):
+        """
+        Test Patch op 'Replace'
+        """
+        # create a new issue with userid 1 in the nosy list and status = 1
+        issue_id = self.db.issue.create(title='foo', nosy=['1'], status='1')
+
+        # replace userid 2 to the nosy list and status = 3
+        form = cgi.FieldStorage()
+        form.list = [
+            cgi.MiniFieldStorage('op', 'replace'),
+            cgi.MiniFieldStorage('nosy', '2'),
+            cgi.MiniFieldStorage('status', '3')
+        ]
+        results = self.server.patch_element('issue', issue_id, form)
+        self.assertEqual(self.dummy_client.response_code, 200)
+
+        # verify the result
+        results = self.server.get_element('issue', issue_id, self.empty_form)
+        results = results['data']
+        self.assertEqual(self.dummy_client.response_code, 200)
+        self.assertEqual(results['attributes']['status'], '3')
+        self.assertEqual(len(results['attributes']['nosy']), 1)
+        self.assertListEqual(results['attributes']['nosy'], ['2'])
+
+    def testPatchRemoveAll(self):
+        """
+        Test Patch Action 'Remove'
+        """
+        # create a new issue with userid 1 and 2 in the nosy list
+        issue_id = self.db.issue.create(title='foo', nosy=['1', '2'])
+
+        # remove the nosy list and the title
+        form = cgi.FieldStorage()
+        form.list = [
+            cgi.MiniFieldStorage('op', 'remove'),
+            cgi.MiniFieldStorage('nosy', ''),
+            cgi.MiniFieldStorage('title', '')
+        ]
+        results = self.server.patch_element('issue', issue_id, form)
+        self.assertEqual(self.dummy_client.response_code, 200)
+
+        # verify the result
+        results = self.server.get_element('issue', issue_id, self.empty_form)
+        results = results['data']
+        self.assertEqual(self.dummy_client.response_code, 200)
+        self.assertEqual(results['attributes']['title'], None)
+        self.assertEqual(len(results['attributes']['nosy']), 0)
+        self.assertEqual(results['attributes']['nosy'], [])
+
+    def testPatchAction(self):
+        """
+        Test Patch Action 'Action'
+        """
+        # create a new issue with userid 1 and 2 in the nosy list
+        issue_id = self.db.issue.create(title='foo')
+
+        # execute action retire
+        form = cgi.FieldStorage()
+        form.list = [
+            cgi.MiniFieldStorage('op', 'action'),
+            cgi.MiniFieldStorage('action_name', 'retire')
+        ]
+        results = self.server.patch_element('issue', issue_id, form)
+        self.assertEqual(self.dummy_client.response_code, 200)
+
+        # verify the result
+        self.assertTrue(self.db.issue.is_retired(issue_id))
+
+    def testPatchRemove(self):
+        """
+        Test Patch Action 'Remove' only some element from a list
+        """
+        # create a new issue with userid 1, 2, 3 in the nosy list
+        issue_id = self.db.issue.create(title='foo', nosy=['1', '2', '3'])
+
+        # remove the nosy list and the title
+        form = cgi.FieldStorage()
+        form.list = [
+            cgi.MiniFieldStorage('op', 'remove'),
+            cgi.MiniFieldStorage('nosy', '1, 2'),
+        ]
+        results = self.server.patch_element('issue', issue_id, form)
+        self.assertEqual(self.dummy_client.response_code, 200)
+
+        # verify the result
+        results = self.server.get_element('issue', issue_id, self.empty_form)
+        results = results['data']
+        self.assertEqual(self.dummy_client.response_code, 200)
+        self.assertEqual(len(results['attributes']['nosy']), 1)
+        self.assertEqual(results['attributes']['nosy'], ['3'])
+
+
+def get_obj(path, id):
+    return {
+        'id': id,
+        'link': path + id
+    }
+
+if __name__ == '__main__':
+    runner = unittest.TextTestRunner()
+    unittest.main(testRunner=runner)

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