source: peerreviewplugin/trunk/codereview/tests/new_review.py

Last change on this file was 18261, checked in by Cinc-th, 2 years ago

PeerReviewPlugin: no longer use CamelCase URLs. Fixed a testcase using unicode strings for Python3.

Refs #14005

File size: 16.7 KB
Line 
1# -*- coding: utf-8 -*-
2# Copyright (c) 2016-2019 Cinc
3# All rights reserved.
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions
7# are met:
8# 1. Redistributions of source code must retain the above copyright
9#    notice, this list of conditions and the following disclaimer.
10# 2. Redistributions in binary form must reproduce the above copyright
11#    notice, this list of conditions and the following disclaimer in the
12#    documentation and/or other materials provided with the distribution.
13# 3. The name of the author may not be used to endorse or promote products
14#    derived from this software without specific prior written permission.
15#
16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27import unittest
28from codereview.model import get_users, ReviewFileModel, PeerReviewModel, PeerReviewerModel, PeerReviewModelProvider
29from codereview.peerReviewNew import add_users_to_data, create_file_hash_id, NewReviewModule
30from datetime import datetime
31from trac.admin.console import TracAdmin
32from trac.test import EnvironmentStub, Mock, MockPerm
33from trac.util.datefmt import to_datetime, to_utimestamp
34
35
36def _add_permissions(env):
37    admin = TracAdmin()
38    admin.env_set('Testenv', env)
39    admin.onecmd("permission add Tester TICKET_VIEW")  # User not allowed to perform code reviews
40    admin.onecmd("permission add Rev1 TRAC_ADMIN")
41    admin.onecmd("permission add Rev2 CODE_REVIEW_DEV")
42    admin.onecmd("permission add Rev3 CODE_REVIEW_MGR")
43    admin.onecmd("permission add Rev1 RevGroup")
44    admin.onecmd("permission add Rev2 RevGroup")
45
46
47def _prepare_review_data(env):
48    # owner, status, created, name, notes, parent_id
49    revs = [
50        ['Rev1', 'bar', to_utimestamp(to_datetime(datetime(2019, 2, 4))), 'name1', 'note1', 0],
51        ['Rev1', 'closed', to_utimestamp(to_datetime(datetime(2019, 3, 4))), 'name2', 'note2', 0],
52        ['Rev2', 'bar', to_utimestamp(to_datetime(datetime(2019, 3, 14))), 'name3', 'note3', 1],
53        ['Rev3', 'foo', to_utimestamp(to_datetime(datetime(2019, 4, 4))), 'name4', 'note4', 2]
54    ]
55
56    with env.db_transaction as db:
57        cursor = db.cursor()
58        for rev in revs:
59            cursor.execute("INSERT INTO peerreview (owner, status, created, name, notes, parent_id) "
60                           "VALUES (%s,%s,%s,%s,%s,%s)", rev)
61
62
63def _prepare_file_data(env):
64    # review_id, path, start, end, revision, status
65    files = [
66        [1, '/foo/bar', 5, 100, '1234', 'new', None, 'repo1'],
67        [1, '/foo/bar2', 6, 101, '1234', 'new', None, 'repo1'],
68        [2, '/foo/bar', 5, 100, '1234', 'closed', None, 'repo1'],
69        [2, '/foo/bar2', 6, 101, '12346', 'closed', None, 'repo1'],
70        [2, '/foo/bar3', 7, 102, '12347', 'closed', None, 'repo1'],
71        [3, '/foo/bar2', 6, 101, '1234', 'new', None, 'repo1'],
72        [4, '/foo/bar', 5, 100, '1234', 'new', None, 'repo1'],
73        [4, '/foo/bar2', 6, 101, '1234', 'new', None, 'repo1'],
74        # File list data for several projects
75        [0, '/foo/bar', 5, 100, '1234', 'new', 'PrjFoo', 'repo1'],
76        [0, '/foo/bar2', 6, 101, '1234', 'new', 'PrjFoo', 'repo1'],
77        [0, '/foo/bar', 5, 100, '1234', 'new', 'PrjBar', 'repo1'],
78        [0, '/foo/bar2', 6, 101, '12346', 'new', 'PrjBar', 'repo1'],
79        [0, '/foo/bar3', 7, 102, '12347', 'new', 'PrjFoo', 'repo1'],
80        [0, '/foo/bar/baz', 6, 101, '1234', 'new', 'PrjBar', 'repo1'],
81        [0, '/foo/bar', 5, 100, '1234', 'new', 'PrjBaz', 'repo1'],
82        [0, '/foo/bar2', 6, 101, '1234', 'new', 'PrjBaz', 'repo1'],
83    ]
84    for f in files:
85        rfm = ReviewFileModel(env)
86        rfm['review_id'] = f[0]
87        rfm['path'] = f[1]
88        rfm['line_start'] = f[2]
89        rfm['line_end'] = f[3]
90        rfm['revision'] = f[4]
91        rfm['status'] = f[5]
92        rfm['project'] = f[6]
93        rfm['repo'] = f[7]
94        rfm.insert()
95
96# reviewer (name), review_id
97names = (['user1', 3], ['user2', 3], ['user3', 3],
98         ['user4', 4], ['user5', 4],
99         ['user4', 2], ['user5', 2],
100         ['user2', 1], ['user3', 1], ['user4', 1], ['user5', 1])
101
102def _prepare_users_for_review(env):
103    for user in names:
104        rev = PeerReviewerModel(env)
105        rev['review_id'] = user[1]
106        rev['reviewer'] = user[0]
107        rev['vote'] = -1
108        rev.insert()
109
110
111class TestCreateFileHashId(unittest.TestCase):
112
113    def test_hash(self):
114
115        f = {
116            'path': "path",
117            'revision': 123,
118            'line_start': 1234,
119            'line_end': 5678,
120            'repo': 'Repo'
121        }
122        self. assertEqual('id1230698611', create_file_hash_id(f))
123
124
125class TestNewReviewModule(unittest.TestCase):
126
127    def _add_permissions(self, env):
128        admin = TracAdmin()
129        admin.env_set('Testenv', env)
130        admin.onecmd("permission add Tester TICKET_VIEW")  # User not allowed to perform code reviews
131        admin.onecmd("permission add Rev1 TRAC_ADMIN")  # This one is also an allowed user
132        admin.onecmd("permission add Rev2 TICKET_VIEW")
133        admin.onecmd("permission add Rev3 TICKET_VIEW")
134        admin.onecmd("permission add Rev1 RevGroup")
135        admin.onecmd("permission add Rev2 RevGroup")
136        for item in set([usr[0] for usr in names]):
137            admin.onecmd("permission add %s CODE_REVIEW_DEV" % item)
138
139    def setUp(self):
140        self.env = EnvironmentStub(default_data=True, enable=['trac.*',
141                                                             'codereview.model.*',
142                                                             'codereview.peerreviewnew.*',
143                                                             'codereview.peerreviewmain.*',
144                                                             'codereview.tracgenericclass.*'])
145        PeerReviewModelProvider(self.env).environment_created()
146        self.plugin = NewReviewModule(self.env)
147        self.req = Mock(href=Mock(), perm=MockPerm(), args={}, authname="Tester")
148        _prepare_review_data(self.env)
149        _prepare_file_data(self.env)
150        _prepare_users_for_review(self.env)
151        self._add_permissions(self.env)
152
153    def tearDown(self):
154        self.env.shutdown()
155
156    def test_get_active_navigation_item(self):
157        self.assertEqual('peerreviewmain', self.plugin.get_active_navigation_item(self.req))
158
159    def test_get_navigation_items(self):
160        self.assertEqual(0, len(self.plugin.get_navigation_items(self.req)))
161
162    def test_save_changes_no_file_check(self):
163        """Test save_changes() method. Only User and review data changes are tested. File changes are ignored."""
164        # args is empty so we have no id for getting a review. Tracgenericclass will complain
165        # when trying to save a review during this method which is not in the database yet.
166        self.assertRaises(AssertionError, self.plugin.save_changes, self.req)
167        # Check data before calling the method
168        rev_pre = PeerReviewModel(self.env, 1)
169        self.assertEqual('note1', rev_pre['notes'])
170        before_users = [item[0] for item in names if item[1] == 1]
171        data = {}
172        add_users_to_data(self.env, 1, data)
173        self.assertItemsEqual(before_users, data['assigned_users'])
174        for item in before_users:
175            self.assertIn(item, data['assigned_users'])
176
177        new_users = ['user3', 'user4', 'user1']
178        self.req.args.update({'oldid': 1,
179                              'Name': 'New name 1',
180                              'Notes': 'New note',
181                              'project': 'PrjBar',
182                              'user': new_users})
183
184        self.plugin.save_changes(self.req)
185        # Check Review data
186        rev = PeerReviewModel(self.env, 1)
187        self.assertEqual('New note', rev['notes'])
188        self.assertEqual('New name 1', rev['name'])
189        self.assertEqual('PrjBar', rev['project'])
190        # Check new assigned user list
191        data = {}
192        add_users_to_data(self.env, 1, data)
193        self.assertItemsEqual(new_users, data['assigned_users'])
194        for item in new_users:
195            self.assertIn(item, data['assigned_users'])
196        # Check if reviewers are correct. Note that two users were removed and a new one added
197        reviewers = list(PeerReviewerModel.select_by_review_id(self.env, 1))
198        self.assertEqual(3, len(reviewers))
199        for rev in reviewers:
200            self.assertIn(rev['reviewer'], new_users)
201
202    def test_save_changes_file_check_only(self):
203        """Test save_changes() method. Only file changes are tested."""
204        # args is empty so we have no id for getting a review. Tracgenericclass will complain
205        # when trying to save a review during this method which is not in the database yet.
206        self.assertRaises(AssertionError, self.plugin.save_changes, self.req)
207        # Check data before calling the method
208        rev_pre = PeerReviewModel(self.env, 1)
209        self.assertEqual('note1', rev_pre['notes'])
210        before_files = list(ReviewFileModel.select_by_review(self.env, 1))
211        self.assertEqual(2, len(before_files))
212        before_users = [item[0] for item in names if item[1] == 1]
213        new_users = before_users
214        # Create the list of files for review 1
215        new_files = []
216        for f in before_files:
217            new_files.append(u"%s,%s,%s,%s,%s" % (f['path'], f['revision'], f['line_start'], f['line_end'], f['repo']))
218        self.req.args.update({'oldid': 1,
219                              'Name': 'New name 1',
220                              'Notes': 'New note',
221                              'project': 'PrjBar',
222                              'user': new_users,
223                              'file': new_files})
224
225        # Test starts here
226        self.plugin.save_changes(self.req)
227        # Simple check of new assigned user list
228        data = {}
229        add_users_to_data(self.env, 1, data)
230        self.assertItemsEqual(before_users, data['assigned_users'])
231        for item in new_users:
232            self.assertIn(item, data['assigned_users'])
233        # Now check files. Note that you only can remove files not add them
234        after_files = list(ReviewFileModel.select_by_review(self.env, 1))
235        self.assertEqual(2, len(after_files))
236        file_list = [item['path'] for item in before_files]
237        for file_ in after_files:
238            self.assertIn(file_['path'], file_list)
239
240        # Now remove one of the files
241        new_files = []
242        for f in before_files[1:]:
243            new_files.append(u"%s,%s,%s,%s,%s" % (f['path'], f['revision'], f['line_start'], f['line_end'], f['repo']))
244        self.req.args['file'] = new_files
245        self.assertEqual(1, len(self.req.args['file']))
246        # Test starts here
247        self.plugin.save_changes(self.req)
248        after_files = list(ReviewFileModel.select_by_review(self.env, 1))
249        self.assertEqual(1, len(after_files))
250
251
252class TestUserHandling(unittest.TestCase):
253
254    def setUp(self):
255        self.env = EnvironmentStub(default_data=True,
256                                   enable=['trac.*',
257                                          'codereview.model.*',
258                                          'codereview.peerreviewnew.*',
259                                          'codereview.peerreviewmain.*',
260                                          'codereview.tracgenericclass.*'])
261        PeerReviewModelProvider(self.env).environment_created()
262        self.plugin = NewReviewModule(self.env)
263        _add_permissions(self.env)
264        reviewer = PeerReviewerModel(self.env)
265        reviewer['review_id'] = 1
266        reviewer['reviewer'] = 'Rev1'
267        reviewer.insert()
268        reviewer = PeerReviewerModel(self.env)
269        reviewer['review_id'] = 1
270        reviewer['reviewer'] = 'Rev2'
271        reviewer.insert()
272
273    def tearDown(self):
274        self.env.shutdown()
275
276    def test_get_code_review_users(self):
277        self.assertEqual(3, len(get_users(self.env)))
278
279    def test_add_users_to_data_dict_no_review(self):
280        data = {}
281        add_users_to_data(self.env, 0, data)
282        self.assertTrue('users' in data)
283        self.assertEqual(3, len(data['users']))
284        # There is no review so we have no assigned users.
285        self.assertTrue('assigned_users' in data)
286        self.assertEqual(0, len(data['assigned_users']))
287
288        self.assertTrue('unassigned_users' in data)
289        self.assertEqual(3, len(data['unassigned_users']))
290        self.assertTrue('emptyList' in data)
291        self.assertEqual(0, data['emptyList'])
292
293    def test_add_users_to_data_dict(self):
294        data = {}
295        add_users_to_data(self.env, 1, data)
296        self.assertTrue('users' in data)
297        self.assertEqual(3, len(data['users']))
298        # There is a review so we have assigned users.
299        self.assertTrue('assigned_users' in data)
300        self.assertEqual(2, len(data['assigned_users']))
301
302        self.assertTrue('unassigned_users' in data)
303        self.assertEqual(1, len(data['unassigned_users']))
304        self.assertTrue('emptyList' in data)
305        self.assertEqual(0, data['emptyList'])
306
307    def test_test_add_users_to_data_dict_prepopulated(self):
308        # data contains the list of users. It shouldn't be changed here.
309        # Note that these users are different than the ones in the other tests.
310        usr_lst = [item[0] for item in names if item[1] == 1]
311        data = {'users': usr_lst}
312        add_users_to_data(self.env, 1, data)
313        self.assertTrue('users' in data)
314        self.assertEqual(4, len(data['users']))
315        for usr in data['users']:
316            self.assertIn(usr, usr_lst)
317
318
319class TestCreateCodeReview(unittest.TestCase):
320
321    @classmethod
322    def setUpClass(cls):
323        cls.env = EnvironmentStub(default_data=True, enable=['trac.*',
324                                                             'codereview.model.*',
325                                                             'codereview.peerreviewnew.*',
326                                                             'codereview.peerreviewmain.*',
327                                                             'codereview.tracgenericclass.*'])
328        PeerReviewModelProvider(cls.env).environment_created()
329        _add_permissions(cls.env)
330        cls.plugin = NewReviewModule(cls.env)
331        cls.req = Mock(href=Mock(), perm=MockPerm())
332        cls.req.authname = 'Tester'
333
334        cls.req.args = {
335            'Name': 'review_name',
336            'Notes': 'review_notes',
337            'project': 'review_project',
338            'user': ['Rev1', 'Rev2'],
339            # 'file': 'path,file_revision,123,789'
340        }
341
342    @classmethod
343    def tearDownClass(cls):
344        cls.env.shutdown()
345
346    def test_create_code_review(self):
347        """Test creation of a new review."""
348        # TODO: do the same for followup reviews
349        review_id = self.plugin.createCodeReview(self.req, 'create')
350        self.assertEqual(1, review_id)
351        review = PeerReviewModel(self.env, review_id)
352        self.assertTrue(isinstance(review, PeerReviewModel))
353        items = [
354            [u'review_name', 'name'],
355            [u'review_notes', 'notes'],
356            [u'review_project', 'project'],
357            [u'Tester', 'owner'],
358            [u'new', 'status'],
359            [0, 'parent_id']
360        ]
361        for item in items:
362            self.assertEqual(item[0], review[item[1]])
363        rm = PeerReviewerModel(self.env)
364        rm.clear_props()
365        rm['review_id'] = review_id
366        reviewers = list(rm.list_matching_objects())
367        self.assertEqual(2, len(reviewers))
368        for rev in reviewers:
369            self.assertEqual(1, rev['review_id'])
370            self.assertTrue(rev['reviewer'] in ['Rev1', 'Rev2'])
371            self.assertEqual(u'new', rev['status'])
372
373
374def test_suite():
375    suite = unittest.TestSuite()
376
377    suite.addTest(unittest.makeSuite(TestCreateFileHashId))
378    suite.addTest(unittest.makeSuite(TestNewReviewModule))
379    suite.addTest(unittest.makeSuite(TestUserHandling))
380    suite.addTest(unittest.makeSuite(TestCreateCodeReview))
381
382    return suite
Note: See TracBrowser for help on using the repository browser.