tests.py 77.7 KB
Newer Older
1
from django.conf import settings
2
from django.test import SimpleTestCase, Client, tag
3
4
from test_plus.test import TestCase, CBVTestCase
from django.urls import reverse, resolve
5
from anonticket.models import UserIdentifier, Project, Issue, GitlabAccountRequest
6
7
from django.contrib.auth.models import User, Group, Permission
# from django.views.generic import TemplateView, DetailView, CreateView, UpdateView
8
from anonticket.views import *
9
10
11
12
13
from anonticket.forms import (
    LoginForm, 
    Anonymous_Ticket_Base_Search_Form,
    Anonymous_Ticket_Project_Search_Form, 
    CreateIssueForm)
14
15
import pprint
pp = pprint.PrettyPrinter(indent=4)
16
from django.core.cache import cache
ViolanteCodes's avatar
ViolanteCodes committed
17

ViolanteCodes's avatar
ViolanteCodes committed
18
# Note: If you run tests with --tag prefix, you can test a small suite
ViolanteCodes's avatar
ViolanteCodes committed
19
20
21
22
# of tests with one of the tags below (registered with '@tag'.)
#   Examples:
#   $ python manage.py test --tag url 
#   (or with coverage) $ coverage run manage.py --tag url.)
ViolanteCodes's avatar
ViolanteCodes committed
23

24
# ---------------------CUSTOM TEST FUNCTIONS----------------------------
ViolanteCodes's avatar
ViolanteCodes committed
25
# Functions used inside of the testing package during rate-limit tests.
26
27
# ----------------------------------------------------------------------

28
def get_testing_limit_rate(fraction=''):
29
30
    """Returns 1 + the number of requests (numerator) from
    settings.LIMIT_RATE or requests/fraction"""
31
32
33
34
    limit_rate = settings.LIMIT_RATE
    limit_list = limit_rate.split('/')
    limit_numerator = limit_list[0]
    limit_numerator = int(limit_numerator)
35
36
37
38
39
40
41
42
43
44
45
    if fraction:
        fraction = float(fraction)
        partial_numerator = fraction * limit_numerator
        partial_numerator = round(partial_numerator)
        partial_numerator += 1
        return partial_numerator
    else:
        limit_numerator += 1
        return limit_numerator

def run_rate_limit_test(self, client, url, form, form_data, follow=False, fraction=''):
46
    """Run successive rate limit tests based on settings.RATE_LIMIT and fraction."""
47
    rate_limit_numerator = get_testing_limit_rate(fraction=fraction)
48
    tries = 0
49
    if fraction:
50
51
52
        print(f"""
        Testing rate limiting: Combined test of {rate_limit_numerator} issues and 
        {rate_limit_numerator} notes.""")
53
54
    else:
        print("""Testing rate limiting.""")
55
    while tries < rate_limit_numerator:
56
        print(f"Trial {tries + 1} of {rate_limit_numerator}.")
57
58
        response = self.client.post(
            path=url, form=form, data=form_data, follow=False)
59
        print(f"Status Code = {response.status_code}")
60
61
62
        tries += 1
    return response

63
64
# -----DISCRETE FUNCTION UNIT TESTS (SHARED FUNCTIONS, NON-GITLAB)------
# Unit tests for the functions inside of views.py in the top section 
ViolanteCodes's avatar
ViolanteCodes committed
65
# labelled: "Shared Functions - Non Gitlab"
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# ----------------------------------------------------------------------
@tag('shared-non-gitlab')
class TestUserIdentifierInDatabase(TestCase):
    """Tests the user_identifier_in_database function."""

    def setUp(self):
        new_user = UserIdentifier.objects.create(user_identifier = 
            'duo-atlas-hypnotism-curry-creatable-rubble'
        )
        self.new_user = new_user

    def test_user_identifier_in_database_good_user(self):
        """Tests user_identifier_in_database with known good user."""
        user_found = user_identifier_in_database(find_user = self.new_user)
        self.assertTrue(user_found)
    
    def test_user_identifier_in_database_bad_user(self):
        """Tests user_identifier_in_database with known bad user."""
        user_found = user_identifier_in_database(find_user = 'i-am-a-known-bad-user')
        self.assertFalse(user_found)

@tag('shared-non-gitlab')
class TestGetUserAsObject(TestCase):
    """Tests the get_user_as_object function"""

    def setUp(self):
        new_user = UserIdentifier.objects.create(user_identifier = 
            'duo-atlas-hypnotism-curry-creatable-rubble'
        )
        self.new_user = new_user

    def test_get_user_as_object(self):
        """Tests user_identifier_in_database with known good user."""
        user_to_find = UserIdentifier.objects.get(user_identifier = self.new_user)
        self.assertEqual(user_to_find.user_identifier, 'duo-atlas-hypnotism-curry-creatable-rubble')

@tag('shared-non-gitlab')
class TestCheckUser(SimpleTestCase):
    """Test the check_user function."""

    def test_check_user_known_good(self):
        """Test the check_user function with known good identifier"""
        user_identifier = 'duo-atlas-hypnotism-curry-creatable-rubble'
        test_response = check_user(user_identifier = user_identifier)
        self.assertTrue(test_response)

    def test_check_user_known_good_uppercase(self):
        """Test the check_user function with known good identifier with uppercase"""
        user_identifier = 'duo-Atlas-hypnotism-Curry-creatable-Rubble'
        test_response = check_user(user_identifier = user_identifier)
        self.assertTrue(test_response)

    def test_check_user_too_many_words(self):
        """Test the check_user function with an identifier that is too long."""
        user_identifier = 'duo-atlas-hypnotism-curry-creatable-rubble-relic-skylight-yield-vocalize-gerbil-finalist'
        test_response = check_user(user_identifier = user_identifier)
        self.assertFalse(test_response)

    def test_check_user_repeated_words(self):
        """Test the check_user function with repeated words"""
        user_identifier = 'duo-atlas-hypnotism-curry-creatable-creatable'
        test_response = check_user(user_identifier = user_identifier)
        self.assertFalse(test_response)

    def test_check_user_bad_words(self):
        """Test the check_user function with repeated words"""
        user_identifier = 'duo-atlas-hypnotism-curry-creatable-foo'
        test_response = check_user(user_identifier = user_identifier)
        self.assertFalse(test_response)
    
136
137
138
139
# ---------------------------URL TESTS----------------------------------
# URL Tests using Django SimpleTestCase (no need for database.)
# ----------------------------------------------------------------------

140
@tag('urls')
141
142
class TestUrls(SimpleTestCase):
    """Test that the URLS in the anonticket resolve."""
143
144
145
    def setUp(self):
        self.new_user = 'duo-atlas-hypnotism-curry-creatable-rubble'
        self.project_slug = 'a-project-slug'
146
147
148
149
150

    def test_home_url_is_resolved(self):
        """Test the 'home' URL."""
        url = reverse('home')
        self.assertEqual(resolve(url).func.view_class, TemplateView)
151
  
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
    def test_create_identifier_url_is_resolved(self):
        """Test the 'create-identifier' URL."""
        url = reverse('create-identifier')
        self.assertEqual(resolve(url).func.view_class, CreateIdentifierView)

    def test_login_url_is_resolved(self):
        """Test the 'login' URL."""
        url = reverse('login')
        self.assertEqual(resolve(url).func, login_view)

    def test_user_login_error_url_is_resolved(self):
        """Test the 'user-login-error URL."""
        url = reverse('user-login-error', args=["bad-identifier"])
        self.assertEqual(resolve(url).func.view_class, UserLoginErrorView)

167
168
169
170
171
172
    def test_create_note_url_is_resolved(self):
        """Test the 'create-note' URL."""
        url = reverse('create-note', args=[
            self.new_user, self.project_slug, 1
        ])
        self.assertEqual(resolve(url).func.view_class, NoteCreateView)
173
174
175
176
177
178
179
180

    def test_issue_detail_view_is_resolved(self):
        """Test the 'issue-detail-view' URL."""
        url = reverse('issue-detail-view', args=[
            'duo-atlas-hypnotism-curry-creatable-rubble',
            740, 1])
        self.assertEqual(resolve(url).func, issue_detail_view)

181
182
183
184
185
186
187
    def test_pending_issue_detail_view_is_resolved(self):
        """Test the 'pending-issue-detail-view' URL."""
        url = reverse('pending-issue-detail-view', args = [
            'duo-atlas-hypnotism-curry-creatable-rubble',
            747, 
            13])
        self.assertEqual(resolve(url).func.view_class, PendingIssueDetailView)
188
189
190
191
192
193
194
195
196
197
198

    def test_issue_search_url_is_resolved(self):
        """Test the 'issue-search' URL."""
        url = reverse('issue-search', args = [
            self.new_user
        ])
        self.assertEqual(resolve(url).func, issue_search_view)

    def test_project_detail_view_url_is_resolved(self):
        """Test the 'project-detail' URL."""
        url = reverse('project-detail', args= [
ViolanteCodes's avatar
ViolanteCodes committed
199
            self.new_user, self.project_slug, 1
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
        ])
        self.assertEqual(resolve(url).func.view_class, ProjectDetailView)

    def test_project_list_is_resolved(self):
        """Test the 'project-list' URL."""
        url = reverse('project-list', args=[
            self.new_user
        ])
        self.assertEqual(resolve(url).func.view_class, ProjectListView)

    def test_issue_created_url_is_resolved(self):
        """Test the 'issue-created' URL."""
        url = reverse('issue-created', args=['duo-atlas-hypnotism-curry-creatable-rubble'])
        self.assertEqual(resolve(url).func.view_class, IssueSuccessView)

    def test_create_issue_url_is_resolved(self):
        """Test the 'create-issue' URL."""
        url = reverse('create-issue', args=['duo-atlas-hypnotism-curry-creatable-rubble'])
        self.assertEqual(resolve(url).func, create_issue_view)
219
        
220
221
222
223
    def test_user_landing_url_is_resolved(self):
        """Test the 'user-landing' URL."""
        url = reverse('user-landing', args=['duo-atlas-hypnotism-curry-creatable-rubble'])
        self.assertEqual(resolve(url).func, user_landing_view)
224

225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
    def test_moderator_url_is_resolved(self):
        """Test the 'moderator' URL."""
        url  = reverse('moderator')
        self.assertEqual(resolve(url).func, moderator_view)

    def test_mod_update_issue_url_is_resolved(self):
        """Test the 'mod-update-issue' url."""
        url = reverse('mod-update-issue', args=[1])
        self.assertEqual(resolve(url).func.view_class, ModeratorIssueUpdateView)
    
    def test_mod_update_note_url_is_resolved(self):
        """Test the 'mod-update-note' url."""
        url = reverse('mod-update-note', args=[1])
        self.assertEqual(resolve(url).func.view_class, ModeratorNoteUpdateView)

240
# --------------------------VIEW TESTS----------------------------------
ViolanteCodes's avatar
ViolanteCodes committed
241
242
# Tests for views: (generally for status = 200, template correct,
# although some POST views also test for redirects, etc.
243
244
# ----------------------------------------------------------------------

245
@tag('id_no_db')
246
class TestIdentifierAndLoginViewsWithoutDatabase(SimpleTestCase):
247
    """Test the functions in views.py under the Identifier and Login
248
    views section that do not require database."""
ViolanteCodes's avatar
ViolanteCodes committed
249
250

    def setUp(self):
251
        # Create a user
252
        self.new_user = 'duo-atlas-hypnotism-curry-creatable-rubble'
253
254
255
256
        self.client = Client()
        self.home_url = reverse('home')
        self.create_identifier_url = reverse('create-identifier')
        self.login_url = reverse('login')
257
        self.user_landing_url = reverse('user-landing', args=[self.new_user])
258
        self.user_login_error_url = reverse('user-login-error', args=["bad-identifier"])
259

260
261
262
263
264
265
    def test_home_view_GET(self):
        """Test the response for home_view"""
        response = self.client.get(self.home_url)
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'anonticket/index.html')

ViolanteCodes's avatar
ViolanteCodes committed
266
267
268
269
270
    def test_create_identifier_view_GET(self):
        """Test the response for create_identifier_view"""
        response = self.client.get(self.create_identifier_url)
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'anonticket/create_identifier.html')
271
272
273
274
275
276
277
    
    def test_login_view_GET(self):
        """Test the response for login_view"""
        response = self.client.get(self.login_url)
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'anonticket/user_login.html')

278
    def test_login_view_GET_with_data(self):
279
280
        """Test the response for the login_view with data."""
        response = self.client.get(self.login_url, data={
281
            'login_string': self.new_user,
282
283
284
        })
        self.assertEqual(response.status_code, 302)

285
    def test_user_landing_view_GET(self):
286
        """Test the response for user_landing_view with known good user_identifier."""
287
288
289
290
        response = self.client.get(self.user_landing_url)
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'anonticket/user_landing.html')

291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
    def test_user_landing_view_GET_seven_words(self):
        """Test the user_landing_view with a known bad identifier 
        (seven words) and verify decorator redirect"""
        too_many_words_url = reverse(
            'user-landing', args=[
                'duo-atlas-hypnotism-curry-creatable-rubble-brunch'])
        response = self. client.get(too_many_words_url)
        self.assertEqual(response.status_code, 302)
    
    def test_user_landing_view_GET_bad_word(self):
        """Test the user_landing_view with a known bad identifier 
        (wrong word) and verify decorator redirect"""
        too_many_words_url = reverse(
            'user-landing', args=[
                'duo-atlas-hypnotism-curry-creatable-moxie'])
        response = self. client.get(too_many_words_url)
        self.assertEqual(response.status_code, 302)

    def test_user_landing_view_GET_repeated_word(self):
        """Test the user_landing_view with a known bad identifier 
        (repeated word) and verify decorator redirect"""
312
        repeated_words_url = reverse(
313
314
            'user-landing', args=[
                'duo-atlas-hypnotism-curry-creatable-creatable'])
315
        response = self.client.get(repeated_words_url)
316
317
        self.assertEqual(response.status_code, 302)

318
319
320
321
322
323
    def test_user_login_error_view_GET(self):
        """Test the response for user_login_error view"""
        response = self.client.get(self.user_login_error_url)
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'anonticket/user_login_error.html')

324
@tag('id_with_db')
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
class TestIdentifierAndLoginViewsWithDatabase(TestCase):
    """ Test the functions in views.py under the Identifier and Login
    views section that require database."""

    def setUp(self):
        """Set up a project, user identifier, and issue in the test database."""
        # Setup project
        new_project = Project(gitlab_id=747)
        # Should fetch gitlab details on save.
        new_project.save()
        # Create a user
        new_user = UserIdentifier.objects.create(
            user_identifier = 'duo-atlas-hypnotism-curry-creatable-rubble'
        )
        # Create a pending issue.
        pending_issue = Issue.objects.create (
            title = 'A Pending Issue',
            linked_project = new_project,
            linked_user = new_user,
            description= 'A description of a pending issue'
        )
        # Create a posted issue.
        posted_issue = Issue.objects.create (  
            title = 'A posted issue',
            description = 'A posted issue description',
            linked_project = new_project,
            linked_user = new_user,
            gitlab_iid = 1,
            reviewer_status = 'A',
            posted_to_GitLab = True
        )
        self.client=Client()
        self.user_landing_url = reverse('user-landing', args=[new_user])

    def test_user_landing_view_GET_with_data(self):
        """Test the response for user_landing_view with known good user_identifier."""
        response = self.client.get(self.user_landing_url)
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'anonticket/user_landing.html')

365
@tag('project')
366
class TestProjectViews(TestCase):
367
    """Test the project functions in views.py minus pagination."""
368
369
370
371
372
373
374
375
376
377
378
379
380
381

    def setUp(self):
        """Set up a project, user identifier, and issue in the test database."""
        # Setup project
        new_project = Project(gitlab_id=747)
        # Should fetch gitlab details on save.
        new_project.save()
        # Create a user
        new_user = UserIdentifier.objects.create(
            user_identifier = 'duo-atlas-hypnotism-curry-creatable-rubble'
        )
        self.client=Client()
        self.project_list_view_url = reverse('project-list', args=[new_user])
        self.project_detail_view_url = reverse('project-detail', args=[
ViolanteCodes's avatar
ViolanteCodes committed
382
            new_user, new_project.slug, 1])
383
384
385
386
387
388
389
        self.new_user = new_user
    
    def test_project_list_GET(self):
        """Test the response for the ProjectListView"""
        response = self.client.get(self.project_list_view_url)
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'anonticket/project_list.html')
390
391
392
393
394
395
396
397
        # Verify template is correctly pulling project 747 from gitlab.
        self.assertInHTML(
            """<a href="/user/duo-atlas-hypnotism-curry-creatable-rubble/projects/anonymous-ticket-portal/page/1">
                    The Tor Project / TPA / Anonymous Ticket Portal</a>""",
            """<td><a href="/user/duo-atlas-hypnotism-curry-creatable-rubble/projects/anonymous-ticket-portal/page/1">
                    The Tor Project / TPA / Anonymous Ticket Portal</a>
                </td>"""
        )
398
399
400
401
402
403
404

    def test_project_detail_GET(self):
        """Test the response for the ProjectDetailView"""
        response = self.client.get(self.project_detail_view_url)
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'anonticket/project_detail.html')

405
406
407
408
409
410
411
412
413
414
415
@tag('pagination')
class TestProjectDetailViewPagination(TestCase):
    """Test the project functions in views.py relating to pagination."""

    def setUp(self):
        """Set up a project, user identifier, and issue in the test database."""
        # Setup project using Tor Project, due to how many total pages of 
        # issues it has.
        tor_project = Project(gitlab_id=426)
        tor_project.save()
        self.tor_project = tor_project
ViolanteCodes's avatar
ViolanteCodes committed
416
        self.gl_project = gl_public.projects.get(426)
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
        self.open_issues_metadata = self.get_issues_metadata('opened')
        self.closed_issues_metadata = self.get_issues_metadata('closed')
        # Get metadata for open issues, including total and pages
        new_user = UserIdentifier.objects.create(
            user_identifier = 'duo-atlas-hypnotism-curry-creatable-rubble'
        )
        self.new_user = new_user
        self.client=Client()
    
    def get_issues_metadata(self, state):
        """Generates the issues generator and passes total issues and
        pages for an issue state into a dictionary."""
        results = {}
        issue_generator = self.gl_project.issues.list(
            as_list=False, state=state
        )
        results[f"total_{state}_issues"] = issue_generator.total
        results[f"total_{state}_pages"] = issue_generator.total_pages
        return results

    def fast_url_get(self, page_number):
        """Give a page number, reverse project detail and grabs the response."""
        url = reverse('project-detail', args = [
            self.new_user, self.tor_project.slug, page_number
        ])
442
        response = self.get(url)
443
444
        return response
    
445
446
447
448
449
450
451
452
453
454
    def run_pagination_test(
        self, 
        page_number, 
        open_links=[], 
        not_open_links=[],
        empty_open_links = [], 
        closed_links=[], 
        not_closed_links=[],
        empty_closed_links = [],
        ):
ViolanteCodes's avatar
ViolanteCodes committed
455
456
        """A battery of pagination tests that tests ProjectDetailView
        context response based on a page_number."""
457
458
        response = self.fast_url_get(page_number)
        self.assertTemplateUsed(response, 'anonticket/project_detail.html')
ViolanteCodes's avatar
ViolanteCodes committed
459
460
461
462
463
464
465
466
467
468
469
470
471
        # Assert user + page number kwargs passed into context
        self.assertEqual(
            response.context['results']['user_identifier'],
            'duo-atlas-hypnotism-curry-creatable-rubble'
        )
        self.assertEqual(
            response.context['page_number'],
            page_number           
        )
        self.assertEqual(
            response.context['gitlab_project'],
            self.gl_project.attributes
        )
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
        # Assert # of open/closed issues matches separate generator call.
        self.assertEqual(
            response.context['open_issues']['total_issues'],
            self.open_issues_metadata['total_opened_issues'])
        self.assertEqual(
            response.context['closed_issues']['total_issues'],
            self.closed_issues_metadata['total_closed_issues']
        )
        # Assert # of open/closed issues PAGES matches separate generator call.
        self.assertEqual(
            response.context['open_issues']['total_pages'],
            self.open_issues_metadata['total_opened_pages'])
        self.assertEqual(
            response.context['closed_issues']['total_pages'],
            self.closed_issues_metadata['total_closed_pages']
        )
        # Assert that the # of open/closed issues ON THIS PAGE matches
        #what it should.
        self.assertEqual(
            len(response.context['open_issues']['issues'].keys()),
            len(self.gl_project.issues.list(state='opened', page=page_number))
        )
        self.assertEqual(
            len(response.context['closed_issues']['issues'].keys()),
496
            len(self.gl_project.issues.list(state='closed', page=page_number))
497
        )
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
        # Pull open_links from context and pass to a dict.
        open_links_dict = response.context['open_issues']
        # check that dict has what it should
        for link in open_links:
            self.assertIn(link, open_links_dict)
        # and not what it shouldn't
        for link in not_open_links:
            self.assertNotIn(link, open_links_dict)
        # and that prev_pages and post_pages are empty as needed
        for link in empty_open_links:
            self.assertEqual(
                open_links_dict[link],
                {}
            )
        # Repeat the same for closed_issues.
        closed_links_dict = response.context['closed_issues']
        for link in closed_links:
            self.assertIn(link, closed_links_dict)
        for link in not_closed_links:
            self.assertNotIn(link, closed_links_dict)
        for link in empty_closed_links:
            self.assertEqual(
                closed_links_dict[link],
                {}
            )
ViolanteCodes's avatar
ViolanteCodes committed
523
524
        # Assign response to self.response to continue testing.
        self.response = response
525
526
527
528

    def test_project_detail_GET_pagination_FIRST_PAGE(self):
        """Test the response for the ProjectDetailView's 
        pagination functions assuming page = 1"""
529
530
        # Set page number and sort context dict keys by whether
        # they should appear or not.
531
        page_number = 1
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
        open_links = [
            'next_url',
            'post_pages',
            'last_page',
        ]
        not_open_links = [
            'first_url',
            'prev_url',
        ]
        empty_open_links = [
            'prev_pages'
        ]
        # Closed links dicts should be same as open as currently on
        # first page.
        closed_links = open_links
        not_closed_links = not_open_links
        empty_closed_links = empty_open_links
        self.run_pagination_test(
            page_number, 
            open_links=open_links, 
            not_open_links = not_open_links,
            empty_open_links = empty_open_links,
            closed_links= closed_links,
            not_closed_links = not_closed_links,
            empty_closed_links= empty_closed_links)
557
        # Check that items specific to template are correct.
ViolanteCodes's avatar
ViolanteCodes committed
558
        # Check no previous link as on page one.
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
        self.assertInHTML(
            """
            <li class="page-item-disabled">
            <span class="page-link">Previous</span></li>""",
            """<ul class="pagination m-0 p-0 justify-content-center">        
            <li class="page-item-disabled">
                <span class="page-link">Previous</span>
            </li></ul> """
        )
        # Test that pagination blocks loads in template with a 'active' current
        # page link.
        self.assertInHTML(
            """
            <li class="page-item active">
                <span class="page-link">
                    1
                </span>
            </li>""",
            """
            <ul class="pagination m-0 p-0 justify-content-center">
            <li class="page-item active">
                <span class="page-link">
                    1
                </span>
            </li>
            </ul>"""
        )

    def test_project_detail_GET_pagination_CURRENT_GREATER_THAN_TOTAL(self):
        """Test ProjectDetailView pagination when page_number > total_pages"""
        page_number = 99999
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
        # Set page number and sort context dict keys by whether
        # they should appear or not.
        open_links = [
            'prev_pages',
            'first_url',
            'prev_url',
        ]
        not_open_links = [
            'next_url',
            'last_page',
            'post_pages',
        ]
        empty_open_links = [
        ]
        # Closed links dicts should be same as open as currently on
        # first page.
        closed_links = open_links
        not_closed_links = not_open_links
        empty_closed_links = empty_open_links
        self.run_pagination_test(
            page_number, 
            open_links=open_links, 
            not_open_links = not_open_links,
            empty_open_links = empty_open_links,
            closed_links= closed_links,
            not_closed_links = not_closed_links,
            empty_closed_links= empty_closed_links)
      
618
    def test_project_detail_GET_pagination_THREE_PAGES_FROM_TOTAL(self):
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
        """Test ProjectDetailView pagination when page_number = 3 pages
        from end for closed issues."""
        # pull total closed pages from metadata and subtract 3
        page_number = self.closed_issues_metadata['total_closed_pages'] - 3
        open_links = [
            'prev_pages',
            'first_url',
            'prev_url',
        ]
        not_open_links = [
            'next_url',
            'last_page',
            'post_pages',
        ]
        empty_open_links = [
        ]
        # Closed links dicts will be different than open_links are there
        # should be more closed issues than open.
        closed_links = [
            'prev_pages',
            'first_url',
            'next_url',
            'post_pages',
        ]
        not_closed_links = [
            'last_page',
        ]
        empty_closed_links = [
        ]
        self.run_pagination_test(
            page_number, 
            open_links=open_links, 
            not_open_links = not_open_links,
            empty_open_links = empty_open_links,
            closed_links= closed_links,
            not_closed_links = not_closed_links,
            empty_closed_links= empty_closed_links,
            )

    def test_project_detail_GET_pagination_PAGE_THIRTY(self):
        """Test ProjectDetailView pagination when page_number = 30."""
        page_number = 30
        open_links = [
            'prev_pages',
            'first_url',
            'post_pages',
            'prev_url',
            'next_url',
            'last_page',
        ]
        not_open_links = [
        ]
        empty_open_links = [
        ]
        # Closed links dicts should be the same as open
        closed_links = open_links
        not_closed_links = not_open_links
        empty_closed_links = empty_open_links
        self.run_pagination_test(
            page_number, 
            open_links=open_links, 
            not_open_links = not_open_links,
            empty_open_links = empty_open_links,
            closed_links= closed_links,
            not_closed_links = not_closed_links,
            empty_closed_links= empty_closed_links,
            )
686

687
@tag('issues')
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
class TestIssuesViews(TestCase):
    """Test the issues functions in views.py"""

    def setUp(self):
        """Set up a project, user identifier, and issue in the test database."""
        # Setup project
        new_project = Project(gitlab_id=747)
        # Should fetch gitlab details on save.
        new_project.save()
        # Create a user
        new_user = UserIdentifier.objects.create(
            user_identifier = 'duo-atlas-hypnotism-curry-creatable-rubble'
        )
        # Create a pending issue.
        pending_issue = Issue.objects.create (
            title = 'A Pending Issue',
            linked_project = new_project,
            linked_user = new_user,
            description= 'A description of a pending issue'
        )
        # Create a posted issue.
        posted_issue = Issue.objects.create (  
            title = 'A posted issue',
            description = 'A posted issue description',
            linked_project = new_project,
            linked_user = new_user,
            gitlab_iid = 1,
            reviewer_status = 'A',
            posted_to_GitLab = True
        )
        self.client=Client()
        self.create_issue_url = reverse('create-issue', args=[new_user])
        self.issue_success_url =  reverse('issue-created', args=[new_user])
        self.pending_issue_url =  reverse('pending-issue-detail-view', args = [
            new_user, new_project.slug, pending_issue.pk])
        self.issue_detail_url = reverse('issue-detail-view', args=[
            new_user, new_project.slug, posted_issue.gitlab_iid])
725
        self.issue_search_url = reverse('issue-search', args=[new_user])
726
        self.new_user = new_user
727
        self.project = new_project
728

729
730
731
732
733
734
    def test_create_issue_GET(self):
        """Test the response for create_issue view"""
        response = self.client.get(self.create_issue_url)
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'anonticket/create_new_issue.html')

735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
    def test_create_issue_POST_current_user(self):
        """Test the response for create_issue view with a current user."""
        form_data = {
            'linked_project': self.project.pk,
            'title':'A new descriptive issue title',
            'description': 'Yet another description of the issue.'
        }
        form=CreateIssueForm(form_data)
        expected_url = reverse('issue-created', args=[self.new_user])
        response = self.client.post(self.create_issue_url, form=form, data=form_data, follow=False)
        self.assertRedirects(response, expected_url)

    def test_create_issue_POST_new_user(self):
        """Test the response for create_issue view with a new user."""
        create_url = reverse('create-issue', args=[
            'autopilot-stunt-unfasten-dirtiness-wipe-blissful'
        ])
        form_data = {
            'linked_project': self.project.pk,
            'title':'A new descriptive issue title',
            'description': 'Yet another description of the issue.'
        }
        form=CreateIssueForm(form_data)
        expected_url = reverse('issue-created', args=[
            'autopilot-stunt-unfasten-dirtiness-wipe-blissful'])
        response = self.client.post(create_url, form=form, data=form_data, follow=False)
        self.assertRedirects(response, expected_url)
762

763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
    def test_issue_success_view_GET(self):
        """Test the response for IssueSuccessView"""
        response = self.client.get(self.issue_success_url)
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'anonticket/create_issue_success.html')
    
    def test_pending_issue_detail_view_GET(self):
        """Test the response for PendingIssueDetailView"""
        response = self.client.get(self.pending_issue_url)
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'anonticket/issue_pending.html')

    def test_issue_detail_view_GET(self):
        """Test the response for issue_detail_view"""
        response = self.client.get(self.issue_detail_url)
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'anonticket/issue_detail.html')
ViolanteCodes's avatar
ViolanteCodes committed
780

ViolanteCodes's avatar
ViolanteCodes committed
781
    def test_issue_search_view_GET_valid_data(self):
782
        """Test the response for the issue_search_view"""
ViolanteCodes's avatar
ViolanteCodes committed
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
        url = reverse('issue-search', args=[self.new_user])
        form_data = {
            'choose_project': self.project.pk,
            'search_terms': 'issue'
        }
        response = self.client.get(url, form_data)
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'anonticket/issue_search.html')

    def test_issue_search_view_GET_invalid_data(self):
        """Test the response for the issue_search_view with no search_terms."""
        url = reverse('issue-search', args=[self.new_user])
        form_data = {
            'choose_project': self.project.pk,
        }
        response = self.client.get(url, form_data)
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'anonticket/issue_search.html')

802
    def test_issue_search_view_GET_no_matches(self):
803
        """Test the response for the issue_search_view"""
804
805
806
807
808
809
810
        url = reverse('issue-search', args=[self.new_user])
        form_data = {
            'choose_project': self.project.pk,
            'search_terms': 'i-dont-match-anything'
        }
        response = self.client.get(url, form_data)
        self.assertEqual(response.status_code, 200)
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
        self.assertTemplateUsed(response, 'anonticket/issue_search.html')

    def tearDown(self):
        """Clear Cache"""
        cache.clear()

@tag('rate-limit-issue')
class TestIssueRateLimit(TestCase):
    """Test the rate-limit function for create_new_issue_view."""

    def setUp(self):
        """Set up a project, user identifier, and issue in the test database."""
        # Setup project
        new_project = Project(gitlab_id=747)
        # Should fetch gitlab details on save.
        new_project.save()
        # Create a user
        new_user = UserIdentifier.objects.create(
            user_identifier = 'duo-atlas-hypnotism-curry-creatable-rubble'
        )
        self.client=Client()
        self.create_issue_url = reverse('create-issue', args=[new_user])
        self.new_user = new_user
        self.project = new_project

    def test_create_issue_POST_new_user_RATE_LIMIT(self):
        """Test rate limit decorators and make exceeding leads to 403."""
        form_data = {
            'linked_project': self.project.pk,
            'title':'A new descriptive issue title',
            'description': 'Yet another description of the issue.'
        }
        form=CreateIssueForm(form_data)
        response = run_rate_limit_test(
            self, self.client, self.create_issue_url, form, form_data
            )
        self.assertEqual(response.status_code, 403)
        self.assertTemplateUsed('anonticket/rate_limit.html')
    
    def tearDown(self):
        """Clear Cache"""
        cache.clear()
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906

@tag('notes')
class TestNotesViews(TestCase):
    """Test the notes functions in views.py."""

    def setUp(self):
        """Set up a project, user identifier, and issue in the test database."""
        # Setup project
        new_project = Project(gitlab_id=747)
        # Should fetch gitlab details on save.
        new_project.save()
        # Create a user
        new_user = UserIdentifier.objects.create(
            user_identifier = 'duo-atlas-hypnotism-curry-creatable-rubble'
        )
        # Create a pending issue.
        pending_issue = Issue.objects.create (
            title = 'A Pending Issue',
            linked_project = new_project,
            linked_user = new_user,
            description= 'A description of a pending issue'
        )
        # Create a posted issue.
        posted_issue = Issue.objects.create (  
            title = 'A posted issue',
            description = 'A posted issue description',
            linked_project = new_project,
            linked_user = new_user,
            gitlab_iid = 1,
            reviewer_status = 'A',
            posted_to_GitLab = True
        )
        self.client=Client()
        self.new_user = new_user
        self.project = new_project
        self.issue = posted_issue

    def test_note_create_view_POST_existing_user(self):
        """Test the note create view with valid data, with a 
        user that already exists."""
        url = reverse('create-note', args=[
            self.new_user, self.project.slug, self.issue.gitlab_iid])
        form_data = {
            'body': """A new note body."""
        }
        expected_url = reverse('issue-created', args=[self.new_user])
        response = self.client.post(url, form_data)
        self.assertRedirects(response, expected_url)

    def test_note_create_view_POST_new_user(self):
        """Test the note create view with valid_data, with a
        user that doesn't get exist."""
        new_user = 'autopilot-stunt-unfasten-dirtiness-wipe-blissful'
        url = reverse('create-note', args=[
907
908
            new_user, self.project.slug, self.issue.gitlab_iid]
            )
909
910
911
912
913
914
        form_data = {
            'body': """A new note body."""
        }
        expected_url = reverse('issue-created', args=[new_user])
        response = self.client.post(url, form_data)
        self.assertRedirects(response, expected_url)
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
    
    def tearDown(self):
        """Clear Cache"""
        cache.clear()

@tag('rate-limit-note')
class TestNoteViewRateLimit(TestCase):
    """Test the ratelimiting for NoteCreateView."""

    def setUp(self):
        """Set up a project, user identifier, and issue in the test database."""
        # Setup project
        new_project = Project(gitlab_id=747)
        # Should fetch gitlab details on save.
        new_project.save()
        # Create a user
        new_user = UserIdentifier.objects.create(
            user_identifier = 'duo-atlas-hypnotism-curry-creatable-rubble'
        )
        # Create a posted issue.
        posted_issue = Issue.objects.create (  
            title = 'A posted issue',
            description = 'A posted issue description',
            linked_project = new_project,
            linked_user = new_user,
            gitlab_iid = 1,
            reviewer_status = 'A',
            posted_to_GitLab = True
        )
        self.client=Client()
        self.new_user = new_user
        self.project = new_project
        self.issue = posted_issue
        
    def test_note_create_view_POST_RATE_LIMIT(self):
        """Test rate limit decorators for note crate view."""
        url = reverse('create-note', args=[
            self.new_user, self.project.slug, self.issue.gitlab_iid])
        form_data = {
            'body': """A new note body."""
        }
956
        form=None
957
958
959
        response = run_rate_limit_test(self, self.client, url, form, form_data)
        self.assertEqual(response.status_code, 403)
        self.assertTemplateUsed('anonticket/rate_limit.html')
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014

    def tearDown(self):
        """Clear Cache"""
        cache.clear()

@tag('rate-limit-combined')
class TestNoteIssueCombinedRateLimit(TestCase):
    """Test that COMBINED rate-limit bucket is working correctly"""

    def setUp(self):
        """Set up a project, user identifier, and issue in the test database."""
        # Setup project
        new_project = Project(gitlab_id=747)
        # Should fetch gitlab details on save.
        new_project.save()
        # Create a user
        new_user = UserIdentifier.objects.create(
            user_identifier = 'duo-atlas-hypnotism-curry-creatable-rubble'
        )
        # Create a posted issue.
        posted_issue = Issue.objects.create (  
            title = 'A posted issue',
            description = 'A posted issue description',
            linked_project = new_project,
            linked_user = new_user,
            gitlab_iid = 1,
            reviewer_status = 'A',
            posted_to_GitLab = True
        )
        self.client=Client()
        self.new_user = new_user
        self.project = new_project
        self.existing_issue = posted_issue
        self.create_issue_url = reverse('create-issue', args=[new_user])
        self.create_note_url = reverse('create-note', args= [
            new_user, new_project.slug, posted_issue.gitlab_iid])

    def test_combined_POST_RATE_LIMIT(self):
        """Test rate limit decorators for note crate view."""
        # Run first 1/2 of trials using issue create
        issue_form_data = {
            'linked_project': self.project.pk,
            'title':'A new descriptive issue title',
            'description': 'Yet another description of the issue.'
        }
        issue_form=CreateIssueForm(issue_form_data)
        issue_response = run_rate_limit_test(
            self, 
            self.client, 
            self.create_issue_url, 
            form=issue_form, 
            form_data=issue_form_data,
            fraction=0.5
            )
        # Assert that status code is 200 at 1/2 + 1 tries.
1015
        self.assertEqual(issue_response.status_code, 302)
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
        # Run second 1/2 of trials using note create
        note_data = {
            'body': """A new note body."""
        }
        note_response = run_rate_limit_test(
            self, 
            self.client, 
            self.create_note_url, 
            form=None,
            form_data=note_data,
            fraction=0.5, 
            )
        # Assert that test now returns 403 forbidden.
        self.assertEqual(note_response.status_code, 403)
        self.assertTemplateUsed('anonticket/rate_limit.html')
1031
1032
1033
1034

    def tearDown(self):
        """Clear Cache"""
        cache.clear()
1035

1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
@tag('gitlab')
class TestGitlabAccountRequestViews(TestCase):
    """Test the views associated with user-created Gitlab
    account requests."""

    def setUp(self):
        """Set up a project, user identifier, and issue in the test database."""
        # Setup project
        new_user = UserIdentifier.objects.create(
            user_identifier = 'duo-atlas-hypnotism-curry-creatable-rubble'
        )
        gitlab_url_no_user = reverse('create-gitlab-no-user')
        gitlab_url_current_user = reverse(
            'create-gitlab-with-user', args=[new_user.user_identifier])
1050
        success_url_no_user = reverse('created-no-user')
1051
1052
1053
1054
        new_user_string = 'nastily-arming-canon-calcium-footsie-jaundice'
        gitlab_url_new_user = reverse(
            'create-gitlab-with-user', args=[new_user_string]
        )
1055
1056
1057
1058
        self.client=Client()
        self.working_user = new_user
        self.gitlab_url_no_user = gitlab_url_no_user
        self.gitlab_url_current_user = gitlab_url_current_user
1059
        self.gitlab_url_new_user = gitlab_url_new_user
1060
        self.success_url_no_user = success_url_no_user
1061
        self.new_user_string = new_user_string
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078

    def test_gitlab_account_create_GET_no_user(self):
        """Test that the GitlabAccountRequestCreateView GET works correctly
        with no user_string in URL path."""
        response = self.client.get(self.gitlab_url_no_user)
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(
            'anonticket/gitlabaccountrequest_user_create.html')
        self.assertInHTML(
            needle="""<h4 class="text-primary pl-3 pr-3">You are not logged in at this time.</h4>""",
            haystack="""<div class="mb-4 form-control p-3 ml-4"> 
            <h4 class="text-primary pl-3 pr-3">You are not logged in 
            at this time.</h4></div>""")

    def test_gitlab_account_create_POST_no_user(self):
        """Test that the GitlabAccountRequestCreateView POST works correctly
        with no user_string in URL path."""
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
        form_data = {
            'username': 'test_username_number_one',
            'email' : 'test@test.com',
            'reason' : "I can't wait to collaborate with TOR!",
        }
        response = self.client.post(self.gitlab_url_no_user, form_data)
        self.assertEqual(response.status_code, 302)
        self.assertRedirects(response, self.success_url_no_user, 302)
        self.assertTemplateUsed('anonticket/create_issue_success.html')
        new_gl_request = GitlabAccountRequest.objects.get(
            username='test_username_number_one')
        self.assertEqual(new_gl_request.email, 'test@test.com')
        self.assertEqual(
            new_gl_request.reason, "I can't wait to collaborate with TOR!")
1093
1094
1095
1096

    def test_gitlab_account_create_GET_new_user(self):
        """Test that the GitlabAccountRequestCreateView GET works correctly
        with a user that does NOT have a current database entry."""
1097

1098
        new_url = reverse(
1099
            'create-gitlab-with-user', args=[self.new_user_string])
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
        response = self.client.get(new_url)
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(
            'anonticket/gitlabaccountrequest_user_create.html')
        self.assertInHTML(
            needle="""<h4 class="pl-3 pr-3">You are logged in as: 
            <span class="text-primary">
            nastily-arming-canon-calcium-footsie-jaundice</span></h4>""",
            haystack="""<div class="mb-4 form-control p-3 ml-4"> 
            <h4 class="pl-3 pr-3">You are logged in as: 
            <span class="text-primary">
            nastily-arming-canon-calcium-footsie-jaundice</span>
            </h4></div>""")
1113
1114
1115
1116

    def test_gitlab_account_create_GET_current_user(self):
        """Test that the GitlabAccountRequestCreateView GET works correctly
        with a user that does have a current database entry."""
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
        response = self.client.get(self.gitlab_url_current_user)
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(
            'anonticket/gitlabaccountrequest_user_create.html')
        self.assertInHTML(
            needle="""<h4 class="pl-3 pr-3">You are logged in as: 
            <span class="text-primary">
            duo-atlas-hypnotism-curry-creatable-rubble</span></h4>""",
            haystack="""<div class="mb-4 form-control p-3 ml-4"> 
            <h4 class="pl-3 pr-3">You are logged in as: 
            <span class="text-primary">
            duo-atlas-hypnotism-curry-creatable-rubble</span>
            </h4></div>""")
1130
1131
1132
1133

    def test_gitlab_account_create_POST_new_user(self):
        """Test that the GitlabAccountRequestCreateView POST works correctly
        with a user that does NOT have a current database entry."""
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
        form_data = {
            'username': 'test_username_number_two',
            'email' : 'test@test.com',
            'reason' : "I can't wait to collaborate with TOR!",
        }
        success_url_new_user = reverse(
            'issue-created', args=[self.new_user_string])
        response = self.client.post(
            self.gitlab_url_new_user, form_data)
        self.assertEqual(response.status_code, 302)
        self.assertRedirects(response, success_url_new_user, 302)
        self.assertTemplateUsed('anonticket/create_issue_success.html')
        new_gl_request = GitlabAccountRequest.objects.get(
            username='test_username_number_two')
        self.assertEqual(new_gl_request.email, 'test@test.com')
        self.assertEqual(
            new_gl_request.reason, "I can't wait to collaborate with TOR!")
1151
1152
1153
1154
1155

    def test_gitlab_account_create_POST_current_user_no_requests(self):
        """Test that the GitlabAccountRequestCreateView GET works correctly
        with a user that does have a current database entry but no
        current GitlabAccountRequests."""
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
        form_data = {
            'username': 'test_username_number_three',
            'email' : 'test@test.com',
            'reason' : "I can't wait to collaborate with TOR!",
        }
        success_url_current_user = reverse(
            'issue-created', args=[self.working_user.user_identifier])
        response = self.client.post(
            self.gitlab_url_current_user, form_data)
        self.assertEqual(response.status_code, 302)
        self.assertRedirects(response, success_url_current_user, 302)
        self.assertTemplateUsed('anonticket/create_issue_success.html')
        new_gl_request = GitlabAccountRequest.objects.get(
            username="test_username_number_three")
        self.assertEqual(new_gl_request.email, 'test@test.com')
        self.assertEqual(
            new_gl_request.reason, "I can't wait to collaborate with TOR!")
1173
1174
1175
1176
1177

    def test_gitlab_account_create_POST_current_user_rejected_request(self):
        """Test that the GitlabAccountRequestCreateView GET works correctly
        with a user that DOES have a current database entry AND has 
        a GitlabAccountRequest, but no PENDING request."""
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
        rejected_request = GitlabAccountRequest.objects.create(
            username='test_username_number_four',
            linked_user=self.working_user, 
            reviewer_status='R',
            email='test@test.com',
            reason="""I can't wait to collaborate with TOR!"""  
        )
        form_data = {
            'username': 'test_username_number_five',
            'email' : 'test@test.com',
            'reason' : "I can't wait to collaborate with TOR!",
        }
        success_url_current_user = reverse(
            'issue-created', args=[self.working_user.user_identifier])
        response = self.client.post(
            self.gitlab_url_current_user, form_data)
        self.assertEqual(response.status_code, 302)
        self.assertRedirects(response, success_url_current_user, 302)
        self.assertTemplateUsed('anonticket/create_issue_success.html')
        new_gl_request = GitlabAccountRequest.objects.get(
            username="test_username_number_five")
        self.assertEqual(new_gl_request.email, 'test@test.com')
        self.assertEqual(
            new_gl_request.reason, "I can't wait to collaborate with TOR!")
1202
1203
1204
1205
1206

    def test_gitlab_account_create_POST_current_user_pending_request(self):
        """Test that the GitlabAccountRequestCreateView GET works correctly
        with a user that DOES have a current database entry AND has 
        a GitlabAccountRequest AND has a PENDING request."""
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
        pending_request = GitlabAccountRequest.objects.create(
            username='test_username_number_six',
            linked_user=self.working_user, 
            reviewer_status='P',
            email='test@test.com',
            reason="""I can't wait to collaborate with TOR!"""  
        )
        form_data = {
            'username': 'test_username_number_seven',
            'email' : 'test@test.com',
            'reason' : "I can't wait to collaborate with TOR!",
        }
        failure_url_current_user = reverse(
            'cannot-create-with-user', args=[self.working_user.user_identifier])
        response = self.client.post(
            self.gitlab_url_current_user, form_data)
        self.assertEqual(response.status_code, 302)
        self.assertRedirects(response, failure_url_current_user, 302)
        self.assertTemplateUsed('anonticket/cannot_create.html')
        # assert object wasn't created
        try_to_get_new_request = GitlabAccountRequest.objects.filter(
            username='test_username_number_seven')
        self.assertEqual(len(try_to_get_new_request), 0)

    def test_gitlab_account_create_POST_invalid_user(self):
        """Test that CreateGitlabAccountRequestView does not allow for
        creation of db objects with a bad user."""

        bad_username_string = 'word-word-word-word-word-word'
        form_data = {
            'username': 'test_username_number_eight',
            'email' : 'test@test.com',
            'reason' : "I can't wait to collaborate with TOR!",
        }
        create_url = reverse('create-gitlab-with-user', args=[bad_username_string])
        login_error_url = reverse('user-login-error', args=[bad_username_string])
        response = self.client.post(create_url, form_data)
        self.assertEqual(response.status_code, 302)
        self.assertRedirects(response, login_error_url, 302)
        self.assertTemplateUsed('anonticket/user_login_error.html')
        # assert object wasn't created
        try_to_get_new_request = GitlabAccountRequest.objects.filter(
            username='test_username_number_eight')
        self.assertEqual(len(try_to_get_new_request), 0)
1251

1252
@tag('other_with_db')
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
class TestViewsOtherWithDatabase(TestCase):
    """Test the functions in views.py not directly related to one of the above
    that require a database."""

    def setUp(self):
        """Set up a project, user identifier, and issue in the test database."""
        new_user = UserIdentifier.objects.create(
            user_identifier = 'duo-atlas-hypnotism-curry-creatable-rubble'
        )
        self.new_user = new_user
1263

1264
1265
    def test_user_identifier_in_database(self):
        """Test user_identifier_in_database function"""
1266
        test_known_good_user = user_identifier_in_database(self.new_user.user_identifier)
1267
1268
1269
1270
1271
        self.assertEqual(test_known_good_user, True)
        known_bad_user = 'test-test-test-test-test-test'
        test_known_bad_user = user_identifier_in_database(known_bad_user)
        self.assertEqual(test_known_bad_user, False)

1272
@tag('other_no_db')
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
class TestViewsOtherWithoutDatabase(SimpleTestCase):
    """Test the functions in views.py not directly related to one of the above
    that do NOT require a database (simpletestcase)."""
    
    def test_get_wordlist(self):
        """Test get_wordlist function."""
        word_list_path = settings.WORD_LIST_PATH
        with open(word_list_path) as f:
            known_wordlist = f.read().splitlines()
        test_wordlist = get_wordlist()
        self.assertEqual(known_wordlist, test_wordlist)

1285
1286
    def test_generate_user_identifier_list(self):
        """Test the generate_user_identifier_list function from CreateIdentifierView."""
1287
1288
        word_list = get_wordlist()
        list_to_test = CreateIdentifierView.generate_user_identifier_list(self)
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
        for word in list_to_test:
            self.assertIn(word, word_list)
    
    def test_context_dict(self):
        """Tests the context_dict function from CreateIdentifierView."""
        words_to_test = [
            'word1',
            'word2',
            'word3',
            'word4',
            'word5',
            'word6',
        ]
        test_context = CreateIdentifierView.context_dict(self, word_list = words_to_test)
        known_context = {
            'chosen_words': words_to_test,            
            'user_identifier_string': 'word1-word2-word3-word4-word5-word6',
        }
        self.assertEqual(test_context, known_context)

    def test_get_context_data(self):
        """Tests the get_context_data function from CreateIdentifierView by verifying the 
        returned results is a dictionary with key['chosen_words'], value = list of 
        settings.DICE_ROLLS words, with all words from wordlist, and key['user_identifier_string'],
        the value of which contains all chosen words. Also asserts that key['user_found'] is 
        not returned (unique user.)"""
        word_list_path = settings.WORD_LIST_PATH
        with open(word_list_path) as f:
            known_wordlist = f.read().splitlines()
        test_create_identifier_view = CreateIdentifierView()
        test_get_context = test_create_identifier_view.get_context_data()
        self.assertTrue(len(test_get_context['chosen_words']) == settings.DICE_ROLLS)
        for word in test_get_context['chosen_words']:
            self.assertIn(word, known_wordlist)
            self.assertIn(word, test_get_context['user_identifier_string'])
        self.assertNotIn('user_found', test_get_context.keys())

ViolanteCodes's avatar
ViolanteCodes committed
1326
# --------------------------FORM TESTS----------------------------------
ViolanteCodes's avatar
ViolanteCodes committed
1327
1328
# Tests for forms.py: basic tests to see that form_is_valid(). Testing
# for integration with views, etc., is done in views.py above.
ViolanteCodes's avatar
ViolanteCodes committed
1329
1330
# ----------------------------------------------------------------------

ViolanteCodes's avatar
ViolanteCodes committed
1331
1332
1333
1334
@tag('login-form')
class TestLoginFormIsValid(SimpleTestCase):
    """Test the is_valid() on Login Form from forms.py, including
    validation errors raised on custom clean method."""
ViolanteCodes's avatar
ViolanteCodes committed
1335

1336
1337
1338
1339
1340
1341
    def test_login_valid_blank(self):
        """Test login form with no data."""
        form = LoginForm(data = {
        })
        self.assertTrue(form.is_valid())

1342
1343
1344
1345
1346
1347
1348
    def test_login_valid_data_login_string(self):
        """Test login form with a valid string."""
        # duo-atlas-hypnotism-curry-creatable-rubble
        form = LoginForm(data = {
            'login_string': 'duo-atlas-hypnotism-curry-creatable-rubble' ,
        })
        self.assertTrue(form.is_valid())
1349

1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
@tag('login-form')
class TestLoginFormAttributes(SimpleTestCase):
    """Test functions of the LoginForm (besides is_valid)"""

    def test_sanitize_login_string_all_dash_no_strip(self):
        """Test sanitize_login_string method with dash 
        separators and no whitespace to strip."""
        form = LoginForm()
        test_phrase = 'duo-atlas-hypnotism-curry-creatable-rubble'
        result = form.sanitize_login_string(test_phrase)
        self.assertEqual(result, 'duo-atlas-hypnotism-curry-creatable-rubble')

    def test_sanitize_login_string_all_space_no_strip(self):
        """Test sanitize_login_string method with space 
        separators and no whitespace to strip."""
        form = LoginForm()
        test_phrase = 'duo atlas hypnotism curry creatable rubble'
        result = form.sanitize_login_string(test_phrase)
        self.assertEqual(result, 'duo-atlas-hypnotism-curry-creatable-rubble')
    
    def test_sanitize_login_string_all_underscore_no_strip(self):
        """Test sanitize_login_string method with underscore 
        separators and no whitespace to strip."""
        form = LoginForm()
        test_phrase = 'duo_atlas_hypnotism_curry_creatable_rubble'
        result = form.sanitize_login_string(test_phrase)
        self.assertEqual(result, 'duo-atlas-hypnotism-curry-creatable-rubble')

    def test_sanitize_login_string_mixed_separator_no_strip(self):
        """Test sanitize_login_string method with mixed 
        separators and no whitespace to strip."""
        form = LoginForm()
        test_phrase = 'duo-atlas hypnotism_curry-creatable rubble'
        result = form.sanitize_login_string(test_phrase)
        self.assertEqual(result, 'duo-atlas-hypnotism-curry-creatable-rubble')

    def test_sanitize_login_string_all_dash_left_strip(self):
        """Test sanitize_login_string method with dash 
        separators and left whitespace to strip."""
        form = LoginForm()
        test_phrase = '      duo-atlas-hypnotism-curry-creatable-rubble'
        result = form.sanitize_login_string(test_phrase)
        self.assertEqual(result, 'duo-atlas-hypnotism-curry-creatable-rubble')

    def test_sanitize_login_string_all_space_right_strip(self):
        """Test sanitize_login_string method with space 
        separators and right whitespace to strip."""
        form = LoginForm()
        test_phrase = 'duo atlas hypnotism curry creatable rubble      '
        result = form.sanitize_login_string(test_phrase)
        self.assertEqual(result, 'duo-atlas-hypnotism-curry-creatable-rubble')
    
    def test_sanitize_login_string_all_underscore_both_strip(self):
        """Test sanitize_login_string method with underscore 
        separators and bilateral whitespace to strip."""
        form = LoginForm()
        test_phrase = '  duo_atlas_hypnotism_curry_creatable_rubble  '
        result = form.sanitize_login_string(test_phrase)
        self.assertEqual(result, 'duo-atlas-hypnotism-curry-creatable-rubble')

    def test_sanitize_login_string_multiple_mixed_separator_both_strip(self):
        """Test sanitize_login_string method with MULTIPLE mixed 
        separators and bilateral whitespace to strip."""
        form = LoginForm()
1414
        test_phrase = '  duo-_-atlas- hypnotism-_-----curry-creatable-,,,,, rubble '
1415
1416
1417
        result = form.sanitize_login_string(test_phrase)
        self.assertEqual(result, 'duo-atlas-hypnotism-curry-creatable-rubble')

1418
@tag('search_form')
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
class TestAnonymousTicketProjectSearchForm(TestCase):
    """Test the Anonymous_Ticket_Project_Search_Form"""

    def setUp(self):
        # Setup project
        new_project = Project(gitlab_id=747)
        # Should fetch gitlab details on save.
        new_project.save()
        self.project = new_project

    def test_project_search_form_valid_data(self):
        """Test the Project Search Form with valid data."""
        form=Anonymous_Ticket_Project_Search_Form(data={
            'choose_project':self.project,
            'search_terms':'issue'
        })
        self.assertTrue(form.is_valid())

    def test_project_search_form_invalid_data(self):
        """Test the Project Search Form with valid data."""
        form=Anonymous_Ticket_Project_Search_Form(data={
        })
        self.assertFalse(form.is_valid())
        self.assertEquals(len(form.errors), 2)

1444
@tag('create_issue_form')
1445
1446
1447
1448
1449
1450
1451
1452
1453
class TestCreateIssueForm(TestCase):
    """Test the CreateIssueForm"""

    def setUp(self):
        # Setup project
        new_project = Project(gitlab_id=747)
        # Should fetch gitlab details on save.
        new_project.save()
        self.project = new_project
1454
1455
1456
1457
1458
1459
        new_user = UserIdentifier.objects.create(
            user_identifier = 'duo-atlas-hypnotism-curry-creatable-rubble'
        )
        self.new_user = new_user
        self.create_issue_url = reverse('create-issue', args=[new_user])
        client=Client()
1460
1461
1462

    def test_create_issue_form_valid_data(self):
        """Test the Project Search Form with valid data."""
1463
        form_data = {
1464
1465
1466
            'linked_project': self.project,
            'title':'A descriptive issue title',
            'description': 'A description of the issue.'
1467
1468
        }
        form=CreateIssueForm(form_data)
1469
1470
1471
1472
1473
1474
1475
1476
1477
        self.assertTrue(form.is_valid())

    def test_create_issue_form_invalid_data(self):
        """Test the Project Search Form with valid data."""
        form=CreateIssueForm(data={
        })
        self.assertFalse(form.is_valid())
        self.assertEquals(len(form.errors), 3)

1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
# ---------------------MODERATOR PORTAL TESTS---------------------------
# Tests for views, etc. associated with the moderator panel.
# ----------------------------------------------------------------------

@tag('moderators')
class TestModeratorViews(TestCase):
    """Test the Views associated with Moderators."""

    def setUp(self):
        # Set Up Moderators group using the create_groups.py file. This
        # will allow test group permissions to exactly match those from file.
        from anonticket.management.commands.create_groups import GROUPS
        from anonticket.management.commands.create_groups import Command as create_groups
1491
        # Add a bad permission call so that you can test this part of the code.
1492
1493
        create_groups.handle(create_groups)
        self.Moderators = Group.objects.get(name="Moderators")
1494
        self.AccountApprovers = Group.objects.get(name="Account Approvers")
1495
1496

        # Set up users to test the staff decorator and is_mod decorator.
1497
1498
        StaffOnly = User.objects.create(
            username='StaffOnly', 
1499
1500
1501
            password='IAmATestPassword',
            is_staff=True
        )
1502
        self.StaffOnly = StaffOnly
1503

1504
1505
        NoStaff = User.objects.create(
            username='NoStaff', 
1506
1507
1508
            password='IAmATestPassword',
            is_staff=False,
        )
1509
1510
        self.NoStaff = NoStaff
        self.Moderators.user_set.add(NoStaff)
1511

1512
1513
        Moderator = User.objects.create(
            username='Moderator', 
1514
1515
1516
            password='IAmATestPassword',
            is_staff=True,
        )
1517
1518
        self.Moderator = Moderator
        self.Moderators.user_set.add(Moderator)
1519

1520
1521
        AccountApprover = User.objects.create(
            username='AccountApprover', 
1522
1523
1524
            password='IAmATestPassword',
            is_staff=True,
        )
1525
1526
        self.AccountApprover = AccountApprover
        self.AccountApprovers.user_set.add(AccountApprover)
1527

1528
        # set the login redirect url for views testing
1529
        from anonticket.views import login_redirect_url as login_redirect_url
1530
1531
1532
1533
1534
1535
        self.login_redirect_url = login_redirect_url
        self.admin_url = '/tor_admin/'
    
    def test_moderators_created_successfully(self):
        """Test that there's a group called Moderators."""
        self.assertEqual(self.Moderators.name, "Moderators")
1536
1537
1538
1539
    
    def test_account_approvers_created_successfully(self):
        """Test that there's a group called Account Approvers."""
        self.assertEqual(self.AccountApprovers.name, "Account Approvers")
1540

1541
    def test_staff_only_created_successfully(self):
1542
        """Check that the username exists, that the user is
1543
1544
1545
1546
1547
        staff, and that the user is NOT part of the Any groups."""
        self.assertEqual(self.StaffOnly.username, "StaffOnly")
        self.assertTrue(self.StaffOnly.is_staff)
        #Check that StaffOnly is not a member of mods or account approvers.
        self.assertFalse(is_mod_or_approver(self.StaffOnly))
1548

1549
    def test_no_staff_created_successfully(self):
1550
1551
        """Test that the username exists, that the user is NOT staff, 
        and that the user IS part of the Moderators group."""
1552
1553
1554
        self.assertEqual(self.NoStaff.username, "NoStaff")
        self.assertFalse(self.NoStaff.is_staff)
        self.assertTrue(is_moderator(self.NoStaff))
1555

1556
    def test_moderator_created_successfully(self):
1557
1558
        """Test that the username exists, that the user IS staff, and that
        the user IS part of the Moderators group."""
1559
1560
1561
        self.assertEqual(self.Moderator.username, "Moderator")
        self.assertTrue(self.Moderator.is_staff)
        self.assertTrue(is_moderator(self.Moderator))
1562

1563
    def test_account_approver_created_successfully(self):
1564
1565
        """Tese that the username exists, that the user is staff, and that
        the user is part of the Account Approvers group."""
1566
1567
1568
1569
        self.assertEqual(self.AccountApprover.username, "AccountApprover")
        self.assertTrue(self.AccountApprover.is_staff)
        self.assertTrue(is_account_approver(self.AccountApprover))
        self.assertFalse(is_moderator(self.AccountApprover))
1570

1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
    def test_moderator_view_GET_not_logged_in(self):
        """Test that the moderator view redirects to a login form
        if there is no logged in user."""
        url = reverse('moderator')
        response = self.client.get(url)
        self.assertRedirects(response, self.login_redirect_url)

    def test_moderator_view_GET_no_group(self):
        """Test that the moderator view redirects to the admin site 
        with no permissions if a user is logged in and a staff member 
1581
        but is not part of the Moderators or Account Approvers Group."""
1582
        current_user = self.StaffOnly
1583
1584
1585
1586
1587
        self.client.force_login(current_user)
        url = reverse('moderator')
        response = self.client.get(url, follow=False)
        self.assertEqual(response.status_code, 302)
        self.assertEqual(response.url, self.login_redirect_url)
1588
1589
        self.assertTemplateNotUsed(response, 'anonticket/moderator.html')

1590
    def test_moderator_view_GET_no_staff(self):
1591
1592
        """Test that the moderator view fails if a user has moderator
        permissions but is not staff."""
1593
        current_user = self.NoStaff
1594
1595
1596
1597
        self.client.force_login(current_user)
        url = reverse('moderator')
        response = self.client.get(url)
        self.assertTemplateNotUsed(response, 'anonticket/moderator.html')
1598
1599
1600
1601

    def test_moderator_view_GET_account_approver(self):
        """Test that the moderator view loads if a user is an account
        approver."""
1602
        current_user = self.AccountApprover
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
        self.client.force_login(current_user)
        url = reverse('moderator')
        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)
        # Assert that the correct template loaded
        self.assertTemplateUsed(response, 'anonticket/moderator.html')
        # But that users in Account Approvers Group and not in Moderators
        # Group do not have access to pending issues.
        self.assertInHTML(
            "You do not have permission to view pending issues at this time.",
            '<p>You do not have permission to view pending issues at this time.</p>')
1614

1615
1616
1617
    def test_moderator_view_GET_valid_moderator(self):
        """Test that the moderator view displays correctly if
        the user has moderator permissions and is staff."""
1618
        current_user = self.Moderator
1619
1620
1621
1622
1623
        self.client.force_login(current_user)
        url = reverse('moderator')
        response = self.client.get(url, follow=True)
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'anonticket/moderator.html')
1624
1625
1626
        self.assertInHTML(
            "You do not have permission to view pending Gitlab account requests at this time.",
            '<p>You do not have permission to view pending Gitlab account requests at this time.</p>')
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
    
    def test_note_update_view_GET_valid_moderator(self):
        """Test that the note update view displays correctly
        for Moderator."""
        # Setup project
        new_project = Project(gitlab_id=747)
        # Should fetch gitlab details on save.
        new_project.save()
        # Create a user
        new_user = UserIdentifier.objects.create(
            user_identifier = 'duo-atlas-hypnotism-curry-creatable-rubble'
        )
        # Create a pending issue.
        pending_issue = Issue.objects.create (
            title = 'A Pending Issue',
            linked_project = new_project,
            linked_user = new_user,
            description= 'A description of a pending issue'
        )
        # Create a posted issue.
        posted_issue = Issue.objects.create (  
            title = 'A posted issue',
            description = 'A posted issue description',
            linked_project = new_project,
            linked_user = new_user,
            gitlab_iid = 1,
            reviewer_status = 'A',
            posted_to_GitLab = True
        )
        pending_note = Note.objects.create(
            body = 'A pending note body',
            linked_project = new_project,
            linked_user = new_user,
            reviewer_status='P',
            issue_iid='1',
        )
        self.client=Client()
        self.new_user = new_user
        self.project = new_project
        self.pending_issue = pending_issue
        self.posted_issue = posted_issue
        self.pending_note = pending_note

1670
        self.client.force_login(self.Moderator)
1671
1672
1673
1674
1675
1676
1677
1678
        url = reverse('pending-note', args=[
            self.new_user,
            self.project.slug, 
            self.pending_note.issue_iid, 
            self.pending_note.pk])
        response = self.client.get(url, follow=True)
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'anonticket/note_pending.html')
1679

1680
1681
1682
1683
1684
1685
1686
1687
1688