| Index: appengine/monorail/tracker/test/tracker_views_test.py
|
| diff --git a/appengine/monorail/tracker/test/tracker_views_test.py b/appengine/monorail/tracker/test/tracker_views_test.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..124aa7f8ca14f03b3e49fad4662d093f5a689c9a
|
| --- /dev/null
|
| +++ b/appengine/monorail/tracker/test/tracker_views_test.py
|
| @@ -0,0 +1,444 @@
|
| +# Copyright 2016 The Chromium Authors. All rights reserved.
|
| +# Use of this source code is govered by a BSD-style
|
| +# license that can be found in the LICENSE file or at
|
| +# https://developers.google.com/open-source/licenses/bsd
|
| +
|
| +"""Unittest for issue tracker views."""
|
| +
|
| +import unittest
|
| +
|
| +import mox
|
| +
|
| +from google.appengine.api import app_identity
|
| +from third_party import ezt
|
| +
|
| +from framework import gcs_helpers
|
| +from framework import urls
|
| +from proto import project_pb2
|
| +from proto import tracker_pb2
|
| +from testing import testing_helpers
|
| +from tracker import tracker_views
|
| +
|
| +
|
| +def _Issue(project_name, local_id, summary, status):
|
| + issue = tracker_pb2.Issue()
|
| + issue.project_name = project_name
|
| + issue.local_id = local_id
|
| + issue.issue_id = 100000 + local_id
|
| + issue.summary = summary
|
| + issue.status = status
|
| + return issue
|
| +
|
| +
|
| +def _MakeConfig():
|
| + config = tracker_pb2.ProjectIssueConfig()
|
| + config.well_known_statuses.append(tracker_pb2.StatusDef(
|
| + status='New', means_open=True))
|
| + config.well_known_statuses.append(tracker_pb2.StatusDef(
|
| + status='Old', means_open=False))
|
| + return config
|
| +
|
| +
|
| +class IssueViewTest(unittest.TestCase):
|
| +
|
| + def setUp(self):
|
| + self.issue1 = _Issue('proj', 1, 'not too long summary', 'New')
|
| + self.issue2 = _Issue('proj', 2, 'sum 2', '')
|
| + self.issue3 = _Issue('proj', 3, 'sum 3', '')
|
| + self.issue4 = _Issue('proj', 4, 'sum 4', '')
|
| +
|
| + self.issue1.reporter_id = 1002
|
| + self.issue1.owner_id = 2002
|
| + self.issue1.labels.extend(['A', 'B'])
|
| + self.issue1.derived_labels.extend(['C', 'D'])
|
| +
|
| + self.issue2.reporter_id = 2002
|
| + self.issue2.labels.extend(['foo', 'bar'])
|
| + self.issue2.blocked_on_iids.extend(
|
| + [self.issue1.issue_id, self.issue3.issue_id])
|
| + self.issue2.blocking_iids.extend(
|
| + [self.issue1.issue_id, self.issue4.issue_id])
|
| + dref = tracker_pb2.DanglingIssueRef()
|
| + dref.project = 'codesite'
|
| + dref.issue_id = 5001
|
| + self.issue2.dangling_blocking_refs.append(dref)
|
| +
|
| + self.issue3.reporter_id = 3002
|
| + self.issue3.labels.extend(['Hot'])
|
| +
|
| + self.issue4.reporter_id = 3002
|
| + self.issue4.labels.extend(['Foo', 'Bar'])
|
| +
|
| + self.restricted = _Issue('proj', 7, 'summary 7', '')
|
| + self.restricted.labels.extend([
|
| + 'Restrict-View-Commit', 'Restrict-View-MyCustomPerm'])
|
| + self.restricted.derived_labels.extend([
|
| + 'Restrict-AddIssueComment-Commit', 'Restrict-EditIssue-Commit',
|
| + 'Restrict-Action-NeededPerm'])
|
| +
|
| + self.users_by_id = {
|
| + 0: 'user 0',
|
| + 1002: 'user 1002',
|
| + 2002: 'user 2002',
|
| + 3002: 'user 3002',
|
| + 4002: 'user 4002',
|
| + }
|
| +
|
| + def CheckSimpleIssueView(self, config):
|
| + view1 = tracker_views.IssueView(
|
| + self.issue1, self.users_by_id, config)
|
| + self.assertEqual('not too long summary', view1.summary)
|
| + self.assertEqual('New', view1.status.name)
|
| + self.assertEqual('user 2002', view1.owner)
|
| + self.assertEqual('A', view1.labels[0].name)
|
| + self.assertEqual('B', view1.labels[1].name)
|
| + self.assertEqual('C', view1.derived_labels[0].name)
|
| + self.assertEqual('D', view1.derived_labels[1].name)
|
| + self.assertEqual([], view1.blocked_on)
|
| + self.assertEqual([], view1.blocking)
|
| + detail_url = '/p/%s%s?id=%d' % (
|
| + self.issue1.project_name, urls.ISSUE_DETAIL,
|
| + self.issue1.local_id)
|
| + self.assertEqual(detail_url, view1.detail_relative_url)
|
| + return view1
|
| +
|
| + def testSimpleIssueView(self):
|
| + config = tracker_pb2.ProjectIssueConfig()
|
| + view1 = self.CheckSimpleIssueView(config)
|
| + self.assertEqual('', view1.status.docstring)
|
| +
|
| + config.well_known_statuses.append(tracker_pb2.StatusDef(
|
| + status='New', status_docstring='Issue has not had review yet'))
|
| + view1 = self.CheckSimpleIssueView(config)
|
| + self.assertEqual('Issue has not had review yet',
|
| + view1.status.docstring)
|
| + self.assertIsNone(view1.restrictions.has_restrictions)
|
| + self.assertEqual('', view1.restrictions.view)
|
| + self.assertEqual('', view1.restrictions.add_comment)
|
| + self.assertEqual('', view1.restrictions.edit)
|
| +
|
| + def testIsOpen(self):
|
| + config = _MakeConfig()
|
| + view1 = tracker_views.IssueView(
|
| + self.issue1, self.users_by_id, config)
|
| + self.assertEqual(ezt.boolean(True), view1.is_open)
|
| +
|
| + self.issue1.status = 'Old'
|
| + view1 = tracker_views.IssueView(
|
| + self.issue1, self.users_by_id, config)
|
| + self.assertEqual(ezt.boolean(False), view1.is_open)
|
| +
|
| + def testIssueViewWithBlocking(self):
|
| + # Treat issues 3 and 4 as visible to the current user.
|
| + view2 = tracker_views.IssueView(
|
| + self.issue2, self.users_by_id, _MakeConfig(),
|
| + open_related={self.issue1.issue_id: self.issue1,
|
| + self.issue3.issue_id: self.issue3},
|
| + closed_related={self.issue4.issue_id: self.issue4})
|
| + self.assertEqual(['not too long summary', 'sum 3'],
|
| + [ref.summary for ref in view2.blocked_on])
|
| + self.assertEqual(['not too long summary', 'sum 4',
|
| + 'Issue 5001 in codesite.'],
|
| + [ref.summary for ref in view2.blocking])
|
| +
|
| + # Now, treat issues 3 and 4 as not visible to the current user.
|
| + view2 = tracker_views.IssueView(
|
| + self.issue2, self.users_by_id, _MakeConfig(),
|
| + open_related={self.issue1.issue_id: self.issue1}, closed_related={})
|
| + self.assertEqual(['not too long summary'],
|
| + [ref.summary for ref in view2.blocked_on])
|
| + self.assertEqual(['not too long summary', 'Issue 5001 in codesite.'],
|
| + [ref.summary for ref in view2.blocking])
|
| +
|
| + # Treat nothing as visible to the current user. Can still see dangling ref.
|
| + view2 = tracker_views.IssueView(
|
| + self.issue2, self.users_by_id, _MakeConfig(),
|
| + open_related={}, closed_related={})
|
| + self.assertEqual([], view2.blocked_on)
|
| + self.assertEqual(['Issue 5001 in codesite.'],
|
| + [ref.summary for ref in view2.blocking])
|
| +
|
| + def testIssueViewWithRestrictions(self):
|
| + view = tracker_views.IssueView(
|
| + self.restricted, self.users_by_id, _MakeConfig())
|
| + self.assertTrue(view.restrictions.has_restrictions)
|
| + self.assertEqual('Commit and MyCustomPerm', view.restrictions.view)
|
| + self.assertEqual('Commit', view.restrictions.add_comment)
|
| + self.assertEqual('Commit', view.restrictions.edit)
|
| + self.assertEqual(['Restrict-Action-NeededPerm'], view.restrictions.other)
|
| + self.assertEqual('Restrict-View-Commit', view.labels[0].name)
|
| + self.assertTrue(view.labels[0].is_restrict)
|
| +
|
| +
|
| +class RestrictionsViewTest(unittest.TestCase):
|
| + pass # TODO(jrobbins): write tests
|
| +
|
| +
|
| +class IssueRefViewTest(unittest.TestCase):
|
| +
|
| + issue1 = testing_helpers.Blank(
|
| + local_id=1,
|
| + project_name='foo',
|
| + summary='blue screen')
|
| + issue2 = testing_helpers.Blank(
|
| + local_id=2,
|
| + project_name='foo',
|
| + summary='hissing noise')
|
| + issue3 = testing_helpers.Blank(
|
| + local_id=3,
|
| + project_name='foo',
|
| + summary='sinking feeling')
|
| + issue4 = testing_helpers.Blank(
|
| + local_id=4,
|
| + project_name='bar',
|
| + summary='aliens among us')
|
| +
|
| + def testNormalCase(self):
|
| + open_list = {1: self.issue1,
|
| + 2: self.issue2}
|
| + closed_list = {3: self.issue3}
|
| +
|
| + ref_iid = 1
|
| + irv = tracker_views.IssueRefView('foo', ref_iid, open_list, closed_list)
|
| + self.assertEquals(irv.visible, ezt.boolean(True))
|
| + self.assertEquals(irv.is_open, ezt.boolean(True))
|
| + self.assertEquals(irv.url, 'detail?id=1')
|
| + self.assertEquals(irv.display_name, 'issue 1')
|
| + self.assertEquals(irv.summary, 'blue screen')
|
| +
|
| + ref_iid = 3
|
| + irv = tracker_views.IssueRefView('foo', ref_iid, open_list, closed_list)
|
| + self.assertEquals(irv.visible, ezt.boolean(True))
|
| + self.assertEquals(irv.is_open, ezt.boolean(False))
|
| + self.assertEquals(irv.url, 'detail?id=3')
|
| + self.assertEquals(irv.display_name, 'issue 3')
|
| + self.assertEquals(irv.summary, 'sinking feeling')
|
| +
|
| + def testMissingIssueShouldNotBeVisible(self):
|
| + open_list = {1: self.issue1,
|
| + 2: self.issue2}
|
| + closed_list = {3: self.issue3}
|
| +
|
| + ref_iid = 99
|
| + irv = tracker_views.IssueRefView('foo', ref_iid, open_list, closed_list)
|
| + self.assertEquals(irv.visible, ezt.boolean(False))
|
| +
|
| + def testCrossProjectReference(self):
|
| + open_list = {1: self.issue1,
|
| + 2: self.issue2}
|
| + closed_list = {3: self.issue3,
|
| + 4: self.issue4}
|
| +
|
| + ref_iid = 4
|
| + irv = tracker_views.IssueRefView('foo', ref_iid, open_list, closed_list)
|
| + self.assertEquals(irv.visible, ezt.boolean(True))
|
| + self.assertEquals(irv.is_open, ezt.boolean(False))
|
| + self.assertEquals(
|
| + irv.url, '/p/bar%s?id=4' % urls.ISSUE_DETAIL)
|
| + self.assertEquals(irv.display_name, 'issue bar:4')
|
| + self.assertEquals(irv.summary, 'aliens among us')
|
| +
|
| +
|
| +class DanglingIssueRefViewTest(unittest.TestCase):
|
| + pass # TODO(jrobbins): write tests
|
| +
|
| +
|
| +class AttachmentViewTest(unittest.TestCase):
|
| +
|
| + def MakeViewAndVerifyFields(
|
| + self, size, name, mimetype, expected_size_str, expect_viewable):
|
| + attach_pb = tracker_pb2.Attachment()
|
| + attach_pb.filesize = size
|
| + attach_pb.attachment_id = 12345
|
| + attach_pb.filename = name
|
| + attach_pb.mimetype = mimetype
|
| +
|
| + view = tracker_views.AttachmentView(attach_pb, 'proj')
|
| + self.assertEqual('/images/paperclip.png', view.iconurl)
|
| + self.assertEqual(expected_size_str, view.filesizestr)
|
| + dl = 'attachment?aid=12345'
|
| + self.assertEqual(dl, view.downloadurl)
|
| + if expect_viewable:
|
| + self.assertEqual(dl + '&inline=1', view.url)
|
| + self.assertEqual(dl + '&inline=1&thumb=1', view.thumbnail_url)
|
| + else:
|
| + self.assertEqual(None, view.url)
|
| + self.assertEqual(None, view.thumbnail_url)
|
| +
|
| + def testNonImage(self):
|
| + self.MakeViewAndVerifyFields(
|
| + 123, 'file.ext', 'funky/bits', '123 bytes', False)
|
| +
|
| + def testViewableImage(self):
|
| + self.MakeViewAndVerifyFields(
|
| + 123, 'logo.gif', 'image/gif', '123 bytes', True)
|
| +
|
| + self.MakeViewAndVerifyFields(
|
| + 123, 'screenshot.jpg', 'image/jpeg', '123 bytes', True)
|
| +
|
| + def testHugeImage(self):
|
| + self.MakeViewAndVerifyFields(
|
| + 18 * 1024 * 1024, 'panorama.png', 'image/jpeg', '18.0 MB', False)
|
| +
|
| + def testViewableText(self):
|
| + name = 'hello.c'
|
| + attach_pb = tracker_pb2.Attachment()
|
| + attach_pb.filesize = 1234
|
| + attach_pb.attachment_id = 12345
|
| + attach_pb.filename = name
|
| + attach_pb.mimetype = 'text/plain'
|
| + view = tracker_views.AttachmentView(attach_pb, 'proj')
|
| +
|
| + view_url = '/p/proj/issues/attachmentText?aid=12345'
|
| + self.assertEqual(view_url, view.url)
|
| +
|
| +
|
| +class LogoViewTest(unittest.TestCase):
|
| +
|
| + def setUp(self):
|
| + self.mox = mox.Mox()
|
| +
|
| + def tearDown(self):
|
| + self.mox.UnsetStubs()
|
| + self.mox.ResetAll()
|
| +
|
| + def testProjectWithLogo(self):
|
| + bucket_name = 'testbucket'
|
| + logo_gcs_id = '123'
|
| + logo_file_name = 'logo.png'
|
| + project_pb = project_pb2.MakeProject(
|
| + 'testProject', logo_gcs_id=logo_gcs_id, logo_file_name=logo_file_name)
|
| + object_path = '/' + bucket_name + logo_gcs_id
|
| +
|
| + self.mox.StubOutWithMock(app_identity, 'get_default_gcs_bucket_name')
|
| + app_identity.get_default_gcs_bucket_name().AndReturn(bucket_name)
|
| +
|
| + self.mox.StubOutWithMock(gcs_helpers, 'SignUrl')
|
| + gcs_helpers.SignUrl(object_path + '-thumbnail').AndReturn('signed/url')
|
| + gcs_helpers.SignUrl(object_path).AndReturn('signed/url')
|
| +
|
| + self.mox.ReplayAll()
|
| +
|
| + view = tracker_views.LogoView(project_pb)
|
| + self.mox.VerifyAll()
|
| + self.assertEquals('logo.png', view.filename)
|
| + self.assertEquals('image/png', view.mimetype)
|
| + self.assertEquals('signed/url', view.thumbnail_url)
|
| + self.assertEquals('signed/url&response-content-displacement=attachment%3B'
|
| + '+filename%3Dlogo.png', view.viewurl)
|
| +
|
| + def testProjectWithNoLogo(self):
|
| + project_pb = project_pb2.MakeProject('testProject')
|
| + view = tracker_views.LogoView(project_pb)
|
| + self.assertEquals('', view.thumbnail_url)
|
| + self.assertEquals('', view.viewurl)
|
| +
|
| +
|
| +class IsViewableImageTest(unittest.TestCase):
|
| +
|
| + def testIsViewableImage(self):
|
| + self.assertTrue(tracker_views.IsViewableImage('image/gif', 123))
|
| + self.assertTrue(tracker_views.IsViewableImage(
|
| + 'image/gif; charset=binary', 123))
|
| + self.assertTrue(tracker_views.IsViewableImage('image/png', 123))
|
| + self.assertTrue(tracker_views.IsViewableImage(
|
| + 'image/png; charset=binary', 123))
|
| + self.assertTrue(tracker_views.IsViewableImage('image/x-png', 123))
|
| + self.assertTrue(tracker_views.IsViewableImage('image/jpeg', 123))
|
| + self.assertTrue(tracker_views.IsViewableImage(
|
| + 'image/jpeg; charset=binary', 123))
|
| + self.assertTrue(tracker_views.IsViewableImage(
|
| + 'image/jpeg', 3 * 1024 * 1024))
|
| +
|
| + self.assertFalse(tracker_views.IsViewableImage('junk/bits', 123))
|
| + self.assertFalse(tracker_views.IsViewableImage(
|
| + 'junk/bits; charset=binary', 123))
|
| + self.assertFalse(tracker_views.IsViewableImage(
|
| + 'image/jpeg', 13 * 1024 * 1024))
|
| +
|
| +
|
| +class IsViewableTextTest(unittest.TestCase):
|
| + pass # TODO(jrobbins): write tests
|
| +
|
| +
|
| +class AmendmentViewTest(unittest.TestCase):
|
| + pass # TODO(jrobbins): write tests
|
| +
|
| +
|
| +class ComponentDefViewTest(unittest.TestCase):
|
| + pass # TODO(jrobbins): write tests
|
| +
|
| +
|
| +class ComponentValueTest(unittest.TestCase):
|
| + pass # TODO(jrobbins): write tests
|
| +
|
| +
|
| +class FieldValueViewTest(unittest.TestCase):
|
| + pass # TODO(jrobbins): write tests
|
| +
|
| +class FieldValueViewTest_Applicability(unittest.TestCase):
|
| + pass # TODO(jrobbins): write tests
|
| +
|
| +
|
| +class MakeFieldValueViewTest(unittest.TestCase):
|
| + pass # TODO(jrobbins): write tests
|
| +
|
| +
|
| +class FindFieldValuesTest(unittest.TestCase):
|
| + pass # TODO(jrobbins): write tests
|
| +
|
| +
|
| +class MakeBounceFieldValueViewsTest(unittest.TestCase):
|
| + pass # TODO(jrobbins): write tests
|
| +
|
| +
|
| +class ConvertLabelsToFieldValuesTest(unittest.TestCase):
|
| +
|
| + def testConvertLabelsToFieldValues_NoLabels(self):
|
| + result = tracker_views._ConvertLabelsToFieldValues(
|
| + [], 'opsys', {})
|
| + self.assertEqual([], result)
|
| +
|
| + def testConvertLabelsToFieldValues_NoMatch(self):
|
| + result = tracker_views._ConvertLabelsToFieldValues(
|
| + ['Pri-3', 'M-44', 'Security', 'Via-Wizard'], 'opsys', {})
|
| + self.assertEqual([], result)
|
| +
|
| + def testConvertLabelsToFieldValues_HasMatch(self):
|
| + result = tracker_views._ConvertLabelsToFieldValues(
|
| + ['Pri-3', 'M-44', 'Security', 'OpSys-OSX'], 'opsys', {})
|
| + self.assertEqual(1, len(result))
|
| + self.assertEqual('OSX', result[0].val)
|
| + self.assertEqual('OSX', result[0].val_short)
|
| + self.assertEqual('', result[0].docstring)
|
| +
|
| + result = tracker_views._ConvertLabelsToFieldValues(
|
| + ['Pri-3', 'M-44', 'Security', 'OpSys-OSX', 'OpSys-All'],
|
| + 'opsys', {'OpSys-All': 'Happens everywhere'})
|
| + self.assertEqual(2, len(result))
|
| + self.assertEqual('OSX', result[0].val)
|
| + self.assertEqual('OSX', result[0].val_short)
|
| + self.assertEqual('', result[0].docstring)
|
| + self.assertEqual('All', result[1].val)
|
| + self.assertEqual('All', result[1].val_short)
|
| + self.assertEqual('Happens everywhere', result[1].docstring)
|
| +
|
| +
|
| +class FieldDefViewTest(unittest.TestCase):
|
| + pass # TODO(jrobbins): write tests
|
| +
|
| +
|
| +class IssueTemplateViewTest(unittest.TestCase):
|
| + pass # TODO(jrobbins): write tests
|
| +
|
| +
|
| +class MakeFieldUserViewsTest(unittest.TestCase):
|
| + pass # TODO(jrobbins): write tests
|
| +
|
| +
|
| +class ConfigViewTest(unittest.TestCase):
|
| + pass # TODO(jrobbins): write tests
|
| +
|
| +
|
| +if __name__ == '__main__':
|
| + unittest.main()
|
|
|