OLD | NEW |
(Empty) | |
| 1 # Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is govered by a BSD-style |
| 3 # license that can be found in the LICENSE file or at |
| 4 # https://developers.google.com/open-source/licenses/bsd |
| 5 |
| 6 """Unittest for issue tracker views.""" |
| 7 |
| 8 import unittest |
| 9 |
| 10 import mox |
| 11 |
| 12 from google.appengine.api import app_identity |
| 13 from third_party import ezt |
| 14 |
| 15 from framework import gcs_helpers |
| 16 from framework import urls |
| 17 from proto import project_pb2 |
| 18 from proto import tracker_pb2 |
| 19 from testing import testing_helpers |
| 20 from tracker import tracker_views |
| 21 |
| 22 |
| 23 def _Issue(project_name, local_id, summary, status): |
| 24 issue = tracker_pb2.Issue() |
| 25 issue.project_name = project_name |
| 26 issue.local_id = local_id |
| 27 issue.issue_id = 100000 + local_id |
| 28 issue.summary = summary |
| 29 issue.status = status |
| 30 return issue |
| 31 |
| 32 |
| 33 def _MakeConfig(): |
| 34 config = tracker_pb2.ProjectIssueConfig() |
| 35 config.well_known_statuses.append(tracker_pb2.StatusDef( |
| 36 status='New', means_open=True)) |
| 37 config.well_known_statuses.append(tracker_pb2.StatusDef( |
| 38 status='Old', means_open=False)) |
| 39 return config |
| 40 |
| 41 |
| 42 class IssueViewTest(unittest.TestCase): |
| 43 |
| 44 def setUp(self): |
| 45 self.issue1 = _Issue('proj', 1, 'not too long summary', 'New') |
| 46 self.issue2 = _Issue('proj', 2, 'sum 2', '') |
| 47 self.issue3 = _Issue('proj', 3, 'sum 3', '') |
| 48 self.issue4 = _Issue('proj', 4, 'sum 4', '') |
| 49 |
| 50 self.issue1.reporter_id = 1002 |
| 51 self.issue1.owner_id = 2002 |
| 52 self.issue1.labels.extend(['A', 'B']) |
| 53 self.issue1.derived_labels.extend(['C', 'D']) |
| 54 |
| 55 self.issue2.reporter_id = 2002 |
| 56 self.issue2.labels.extend(['foo', 'bar']) |
| 57 self.issue2.blocked_on_iids.extend( |
| 58 [self.issue1.issue_id, self.issue3.issue_id]) |
| 59 self.issue2.blocking_iids.extend( |
| 60 [self.issue1.issue_id, self.issue4.issue_id]) |
| 61 dref = tracker_pb2.DanglingIssueRef() |
| 62 dref.project = 'codesite' |
| 63 dref.issue_id = 5001 |
| 64 self.issue2.dangling_blocking_refs.append(dref) |
| 65 |
| 66 self.issue3.reporter_id = 3002 |
| 67 self.issue3.labels.extend(['Hot']) |
| 68 |
| 69 self.issue4.reporter_id = 3002 |
| 70 self.issue4.labels.extend(['Foo', 'Bar']) |
| 71 |
| 72 self.restricted = _Issue('proj', 7, 'summary 7', '') |
| 73 self.restricted.labels.extend([ |
| 74 'Restrict-View-Commit', 'Restrict-View-MyCustomPerm']) |
| 75 self.restricted.derived_labels.extend([ |
| 76 'Restrict-AddIssueComment-Commit', 'Restrict-EditIssue-Commit', |
| 77 'Restrict-Action-NeededPerm']) |
| 78 |
| 79 self.users_by_id = { |
| 80 0: 'user 0', |
| 81 1002: 'user 1002', |
| 82 2002: 'user 2002', |
| 83 3002: 'user 3002', |
| 84 4002: 'user 4002', |
| 85 } |
| 86 |
| 87 def CheckSimpleIssueView(self, config): |
| 88 view1 = tracker_views.IssueView( |
| 89 self.issue1, self.users_by_id, config) |
| 90 self.assertEqual('not too long summary', view1.summary) |
| 91 self.assertEqual('New', view1.status.name) |
| 92 self.assertEqual('user 2002', view1.owner) |
| 93 self.assertEqual('A', view1.labels[0].name) |
| 94 self.assertEqual('B', view1.labels[1].name) |
| 95 self.assertEqual('C', view1.derived_labels[0].name) |
| 96 self.assertEqual('D', view1.derived_labels[1].name) |
| 97 self.assertEqual([], view1.blocked_on) |
| 98 self.assertEqual([], view1.blocking) |
| 99 detail_url = '/p/%s%s?id=%d' % ( |
| 100 self.issue1.project_name, urls.ISSUE_DETAIL, |
| 101 self.issue1.local_id) |
| 102 self.assertEqual(detail_url, view1.detail_relative_url) |
| 103 return view1 |
| 104 |
| 105 def testSimpleIssueView(self): |
| 106 config = tracker_pb2.ProjectIssueConfig() |
| 107 view1 = self.CheckSimpleIssueView(config) |
| 108 self.assertEqual('', view1.status.docstring) |
| 109 |
| 110 config.well_known_statuses.append(tracker_pb2.StatusDef( |
| 111 status='New', status_docstring='Issue has not had review yet')) |
| 112 view1 = self.CheckSimpleIssueView(config) |
| 113 self.assertEqual('Issue has not had review yet', |
| 114 view1.status.docstring) |
| 115 self.assertIsNone(view1.restrictions.has_restrictions) |
| 116 self.assertEqual('', view1.restrictions.view) |
| 117 self.assertEqual('', view1.restrictions.add_comment) |
| 118 self.assertEqual('', view1.restrictions.edit) |
| 119 |
| 120 def testIsOpen(self): |
| 121 config = _MakeConfig() |
| 122 view1 = tracker_views.IssueView( |
| 123 self.issue1, self.users_by_id, config) |
| 124 self.assertEqual(ezt.boolean(True), view1.is_open) |
| 125 |
| 126 self.issue1.status = 'Old' |
| 127 view1 = tracker_views.IssueView( |
| 128 self.issue1, self.users_by_id, config) |
| 129 self.assertEqual(ezt.boolean(False), view1.is_open) |
| 130 |
| 131 def testIssueViewWithBlocking(self): |
| 132 # Treat issues 3 and 4 as visible to the current user. |
| 133 view2 = tracker_views.IssueView( |
| 134 self.issue2, self.users_by_id, _MakeConfig(), |
| 135 open_related={self.issue1.issue_id: self.issue1, |
| 136 self.issue3.issue_id: self.issue3}, |
| 137 closed_related={self.issue4.issue_id: self.issue4}) |
| 138 self.assertEqual(['not too long summary', 'sum 3'], |
| 139 [ref.summary for ref in view2.blocked_on]) |
| 140 self.assertEqual(['not too long summary', 'sum 4', |
| 141 'Issue 5001 in codesite.'], |
| 142 [ref.summary for ref in view2.blocking]) |
| 143 |
| 144 # Now, treat issues 3 and 4 as not visible to the current user. |
| 145 view2 = tracker_views.IssueView( |
| 146 self.issue2, self.users_by_id, _MakeConfig(), |
| 147 open_related={self.issue1.issue_id: self.issue1}, closed_related={}) |
| 148 self.assertEqual(['not too long summary'], |
| 149 [ref.summary for ref in view2.blocked_on]) |
| 150 self.assertEqual(['not too long summary', 'Issue 5001 in codesite.'], |
| 151 [ref.summary for ref in view2.blocking]) |
| 152 |
| 153 # Treat nothing as visible to the current user. Can still see dangling ref. |
| 154 view2 = tracker_views.IssueView( |
| 155 self.issue2, self.users_by_id, _MakeConfig(), |
| 156 open_related={}, closed_related={}) |
| 157 self.assertEqual([], view2.blocked_on) |
| 158 self.assertEqual(['Issue 5001 in codesite.'], |
| 159 [ref.summary for ref in view2.blocking]) |
| 160 |
| 161 def testIssueViewWithRestrictions(self): |
| 162 view = tracker_views.IssueView( |
| 163 self.restricted, self.users_by_id, _MakeConfig()) |
| 164 self.assertTrue(view.restrictions.has_restrictions) |
| 165 self.assertEqual('Commit and MyCustomPerm', view.restrictions.view) |
| 166 self.assertEqual('Commit', view.restrictions.add_comment) |
| 167 self.assertEqual('Commit', view.restrictions.edit) |
| 168 self.assertEqual(['Restrict-Action-NeededPerm'], view.restrictions.other) |
| 169 self.assertEqual('Restrict-View-Commit', view.labels[0].name) |
| 170 self.assertTrue(view.labels[0].is_restrict) |
| 171 |
| 172 |
| 173 class RestrictionsViewTest(unittest.TestCase): |
| 174 pass # TODO(jrobbins): write tests |
| 175 |
| 176 |
| 177 class IssueRefViewTest(unittest.TestCase): |
| 178 |
| 179 issue1 = testing_helpers.Blank( |
| 180 local_id=1, |
| 181 project_name='foo', |
| 182 summary='blue screen') |
| 183 issue2 = testing_helpers.Blank( |
| 184 local_id=2, |
| 185 project_name='foo', |
| 186 summary='hissing noise') |
| 187 issue3 = testing_helpers.Blank( |
| 188 local_id=3, |
| 189 project_name='foo', |
| 190 summary='sinking feeling') |
| 191 issue4 = testing_helpers.Blank( |
| 192 local_id=4, |
| 193 project_name='bar', |
| 194 summary='aliens among us') |
| 195 |
| 196 def testNormalCase(self): |
| 197 open_list = {1: self.issue1, |
| 198 2: self.issue2} |
| 199 closed_list = {3: self.issue3} |
| 200 |
| 201 ref_iid = 1 |
| 202 irv = tracker_views.IssueRefView('foo', ref_iid, open_list, closed_list) |
| 203 self.assertEquals(irv.visible, ezt.boolean(True)) |
| 204 self.assertEquals(irv.is_open, ezt.boolean(True)) |
| 205 self.assertEquals(irv.url, 'detail?id=1') |
| 206 self.assertEquals(irv.display_name, 'issue 1') |
| 207 self.assertEquals(irv.summary, 'blue screen') |
| 208 |
| 209 ref_iid = 3 |
| 210 irv = tracker_views.IssueRefView('foo', ref_iid, open_list, closed_list) |
| 211 self.assertEquals(irv.visible, ezt.boolean(True)) |
| 212 self.assertEquals(irv.is_open, ezt.boolean(False)) |
| 213 self.assertEquals(irv.url, 'detail?id=3') |
| 214 self.assertEquals(irv.display_name, 'issue 3') |
| 215 self.assertEquals(irv.summary, 'sinking feeling') |
| 216 |
| 217 def testMissingIssueShouldNotBeVisible(self): |
| 218 open_list = {1: self.issue1, |
| 219 2: self.issue2} |
| 220 closed_list = {3: self.issue3} |
| 221 |
| 222 ref_iid = 99 |
| 223 irv = tracker_views.IssueRefView('foo', ref_iid, open_list, closed_list) |
| 224 self.assertEquals(irv.visible, ezt.boolean(False)) |
| 225 |
| 226 def testCrossProjectReference(self): |
| 227 open_list = {1: self.issue1, |
| 228 2: self.issue2} |
| 229 closed_list = {3: self.issue3, |
| 230 4: self.issue4} |
| 231 |
| 232 ref_iid = 4 |
| 233 irv = tracker_views.IssueRefView('foo', ref_iid, open_list, closed_list) |
| 234 self.assertEquals(irv.visible, ezt.boolean(True)) |
| 235 self.assertEquals(irv.is_open, ezt.boolean(False)) |
| 236 self.assertEquals( |
| 237 irv.url, '/p/bar%s?id=4' % urls.ISSUE_DETAIL) |
| 238 self.assertEquals(irv.display_name, 'issue bar:4') |
| 239 self.assertEquals(irv.summary, 'aliens among us') |
| 240 |
| 241 |
| 242 class DanglingIssueRefViewTest(unittest.TestCase): |
| 243 pass # TODO(jrobbins): write tests |
| 244 |
| 245 |
| 246 class AttachmentViewTest(unittest.TestCase): |
| 247 |
| 248 def MakeViewAndVerifyFields( |
| 249 self, size, name, mimetype, expected_size_str, expect_viewable): |
| 250 attach_pb = tracker_pb2.Attachment() |
| 251 attach_pb.filesize = size |
| 252 attach_pb.attachment_id = 12345 |
| 253 attach_pb.filename = name |
| 254 attach_pb.mimetype = mimetype |
| 255 |
| 256 view = tracker_views.AttachmentView(attach_pb, 'proj') |
| 257 self.assertEqual('/images/paperclip.png', view.iconurl) |
| 258 self.assertEqual(expected_size_str, view.filesizestr) |
| 259 dl = 'attachment?aid=12345' |
| 260 self.assertEqual(dl, view.downloadurl) |
| 261 if expect_viewable: |
| 262 self.assertEqual(dl + '&inline=1', view.url) |
| 263 self.assertEqual(dl + '&inline=1&thumb=1', view.thumbnail_url) |
| 264 else: |
| 265 self.assertEqual(None, view.url) |
| 266 self.assertEqual(None, view.thumbnail_url) |
| 267 |
| 268 def testNonImage(self): |
| 269 self.MakeViewAndVerifyFields( |
| 270 123, 'file.ext', 'funky/bits', '123 bytes', False) |
| 271 |
| 272 def testViewableImage(self): |
| 273 self.MakeViewAndVerifyFields( |
| 274 123, 'logo.gif', 'image/gif', '123 bytes', True) |
| 275 |
| 276 self.MakeViewAndVerifyFields( |
| 277 123, 'screenshot.jpg', 'image/jpeg', '123 bytes', True) |
| 278 |
| 279 def testHugeImage(self): |
| 280 self.MakeViewAndVerifyFields( |
| 281 18 * 1024 * 1024, 'panorama.png', 'image/jpeg', '18.0 MB', False) |
| 282 |
| 283 def testViewableText(self): |
| 284 name = 'hello.c' |
| 285 attach_pb = tracker_pb2.Attachment() |
| 286 attach_pb.filesize = 1234 |
| 287 attach_pb.attachment_id = 12345 |
| 288 attach_pb.filename = name |
| 289 attach_pb.mimetype = 'text/plain' |
| 290 view = tracker_views.AttachmentView(attach_pb, 'proj') |
| 291 |
| 292 view_url = '/p/proj/issues/attachmentText?aid=12345' |
| 293 self.assertEqual(view_url, view.url) |
| 294 |
| 295 |
| 296 class LogoViewTest(unittest.TestCase): |
| 297 |
| 298 def setUp(self): |
| 299 self.mox = mox.Mox() |
| 300 |
| 301 def tearDown(self): |
| 302 self.mox.UnsetStubs() |
| 303 self.mox.ResetAll() |
| 304 |
| 305 def testProjectWithLogo(self): |
| 306 bucket_name = 'testbucket' |
| 307 logo_gcs_id = '123' |
| 308 logo_file_name = 'logo.png' |
| 309 project_pb = project_pb2.MakeProject( |
| 310 'testProject', logo_gcs_id=logo_gcs_id, logo_file_name=logo_file_name) |
| 311 object_path = '/' + bucket_name + logo_gcs_id |
| 312 |
| 313 self.mox.StubOutWithMock(app_identity, 'get_default_gcs_bucket_name') |
| 314 app_identity.get_default_gcs_bucket_name().AndReturn(bucket_name) |
| 315 |
| 316 self.mox.StubOutWithMock(gcs_helpers, 'SignUrl') |
| 317 gcs_helpers.SignUrl(object_path + '-thumbnail').AndReturn('signed/url') |
| 318 gcs_helpers.SignUrl(object_path).AndReturn('signed/url') |
| 319 |
| 320 self.mox.ReplayAll() |
| 321 |
| 322 view = tracker_views.LogoView(project_pb) |
| 323 self.mox.VerifyAll() |
| 324 self.assertEquals('logo.png', view.filename) |
| 325 self.assertEquals('image/png', view.mimetype) |
| 326 self.assertEquals('signed/url', view.thumbnail_url) |
| 327 self.assertEquals('signed/url&response-content-displacement=attachment%3B' |
| 328 '+filename%3Dlogo.png', view.viewurl) |
| 329 |
| 330 def testProjectWithNoLogo(self): |
| 331 project_pb = project_pb2.MakeProject('testProject') |
| 332 view = tracker_views.LogoView(project_pb) |
| 333 self.assertEquals('', view.thumbnail_url) |
| 334 self.assertEquals('', view.viewurl) |
| 335 |
| 336 |
| 337 class IsViewableImageTest(unittest.TestCase): |
| 338 |
| 339 def testIsViewableImage(self): |
| 340 self.assertTrue(tracker_views.IsViewableImage('image/gif', 123)) |
| 341 self.assertTrue(tracker_views.IsViewableImage( |
| 342 'image/gif; charset=binary', 123)) |
| 343 self.assertTrue(tracker_views.IsViewableImage('image/png', 123)) |
| 344 self.assertTrue(tracker_views.IsViewableImage( |
| 345 'image/png; charset=binary', 123)) |
| 346 self.assertTrue(tracker_views.IsViewableImage('image/x-png', 123)) |
| 347 self.assertTrue(tracker_views.IsViewableImage('image/jpeg', 123)) |
| 348 self.assertTrue(tracker_views.IsViewableImage( |
| 349 'image/jpeg; charset=binary', 123)) |
| 350 self.assertTrue(tracker_views.IsViewableImage( |
| 351 'image/jpeg', 3 * 1024 * 1024)) |
| 352 |
| 353 self.assertFalse(tracker_views.IsViewableImage('junk/bits', 123)) |
| 354 self.assertFalse(tracker_views.IsViewableImage( |
| 355 'junk/bits; charset=binary', 123)) |
| 356 self.assertFalse(tracker_views.IsViewableImage( |
| 357 'image/jpeg', 13 * 1024 * 1024)) |
| 358 |
| 359 |
| 360 class IsViewableTextTest(unittest.TestCase): |
| 361 pass # TODO(jrobbins): write tests |
| 362 |
| 363 |
| 364 class AmendmentViewTest(unittest.TestCase): |
| 365 pass # TODO(jrobbins): write tests |
| 366 |
| 367 |
| 368 class ComponentDefViewTest(unittest.TestCase): |
| 369 pass # TODO(jrobbins): write tests |
| 370 |
| 371 |
| 372 class ComponentValueTest(unittest.TestCase): |
| 373 pass # TODO(jrobbins): write tests |
| 374 |
| 375 |
| 376 class FieldValueViewTest(unittest.TestCase): |
| 377 pass # TODO(jrobbins): write tests |
| 378 |
| 379 class FieldValueViewTest_Applicability(unittest.TestCase): |
| 380 pass # TODO(jrobbins): write tests |
| 381 |
| 382 |
| 383 class MakeFieldValueViewTest(unittest.TestCase): |
| 384 pass # TODO(jrobbins): write tests |
| 385 |
| 386 |
| 387 class FindFieldValuesTest(unittest.TestCase): |
| 388 pass # TODO(jrobbins): write tests |
| 389 |
| 390 |
| 391 class MakeBounceFieldValueViewsTest(unittest.TestCase): |
| 392 pass # TODO(jrobbins): write tests |
| 393 |
| 394 |
| 395 class ConvertLabelsToFieldValuesTest(unittest.TestCase): |
| 396 |
| 397 def testConvertLabelsToFieldValues_NoLabels(self): |
| 398 result = tracker_views._ConvertLabelsToFieldValues( |
| 399 [], 'opsys', {}) |
| 400 self.assertEqual([], result) |
| 401 |
| 402 def testConvertLabelsToFieldValues_NoMatch(self): |
| 403 result = tracker_views._ConvertLabelsToFieldValues( |
| 404 ['Pri-3', 'M-44', 'Security', 'Via-Wizard'], 'opsys', {}) |
| 405 self.assertEqual([], result) |
| 406 |
| 407 def testConvertLabelsToFieldValues_HasMatch(self): |
| 408 result = tracker_views._ConvertLabelsToFieldValues( |
| 409 ['Pri-3', 'M-44', 'Security', 'OpSys-OSX'], 'opsys', {}) |
| 410 self.assertEqual(1, len(result)) |
| 411 self.assertEqual('OSX', result[0].val) |
| 412 self.assertEqual('OSX', result[0].val_short) |
| 413 self.assertEqual('', result[0].docstring) |
| 414 |
| 415 result = tracker_views._ConvertLabelsToFieldValues( |
| 416 ['Pri-3', 'M-44', 'Security', 'OpSys-OSX', 'OpSys-All'], |
| 417 'opsys', {'OpSys-All': 'Happens everywhere'}) |
| 418 self.assertEqual(2, len(result)) |
| 419 self.assertEqual('OSX', result[0].val) |
| 420 self.assertEqual('OSX', result[0].val_short) |
| 421 self.assertEqual('', result[0].docstring) |
| 422 self.assertEqual('All', result[1].val) |
| 423 self.assertEqual('All', result[1].val_short) |
| 424 self.assertEqual('Happens everywhere', result[1].docstring) |
| 425 |
| 426 |
| 427 class FieldDefViewTest(unittest.TestCase): |
| 428 pass # TODO(jrobbins): write tests |
| 429 |
| 430 |
| 431 class IssueTemplateViewTest(unittest.TestCase): |
| 432 pass # TODO(jrobbins): write tests |
| 433 |
| 434 |
| 435 class MakeFieldUserViewsTest(unittest.TestCase): |
| 436 pass # TODO(jrobbins): write tests |
| 437 |
| 438 |
| 439 class ConfigViewTest(unittest.TestCase): |
| 440 pass # TODO(jrobbins): write tests |
| 441 |
| 442 |
| 443 if __name__ == '__main__': |
| 444 unittest.main() |
OLD | NEW |