@ -2,8 +2,11 @@ from unittest.mock import patch
import ldap3
import pytest
import datetime
import ceod . utils as utils
import ceod . utils
import ceo_common . utils
from ceo_common . model import Term
def test_api_user_not_found ( client ) :
@ -12,26 +15,26 @@ def test_api_user_not_found(client):
@pytest . fixture ( scope = ' module ' )
def create_user_resp ( client , mocks_for_create_user , mock_mail_server ) :
def create_user_resp ( client , mocks_for_create_user_module , mock_mail_server ) :
mock_mail_server . messages . clear ( )
status , data = client . post ( ' /api/members ' , json = {
' uid ' : ' test_ 1 ' ,
' uid ' : ' test1 ' ,
' cn ' : ' Test One ' ,
' given_name ' : ' Test ' ,
' sn ' : ' One ' ,
' program ' : ' Math ' ,
' terms ' : [ ' s2021 ' ] ,
' forwarding_addresses ' : [ ' test_ 1@uwaterloo.internal ' ] ,
' forwarding_addresses ' : [ ' test1@uwaterloo.internal ' ] ,
} )
assert status == 200
assert data [ - 1 ] [ ' status ' ] == ' completed '
yield status , data
status , data = client . delete ( ' /api/members/test_ 1 ' )
status , data = client . delete ( ' /api/members/test1 ' )
assert status == 200
assert data [ - 1 ] [ ' status ' ] == ' completed '
@pytest . fixture ( scope = ' module ' )
@pytest . fixture ( scope = ' function ' )
def create_user_result ( create_user_resp ) :
# convenience method
_ , data = create_user_resp
@ -54,25 +57,26 @@ def test_api_create_user(cfg, create_user_resp, mock_mail_server):
" cn " : " Test One " ,
" given_name " : " Test " ,
" sn " : " One " ,
" uid " : " test_ 1 " ,
" uid " : " test1 " ,
" uid_number " : min_uid ,
" gid_number " : min_uid ,
" login_shell " : " /bin/bash " ,
" home_directory " : " /tmp/test_users/test_ 1 " ,
" home_directory " : " /tmp/test_users/test1 " ,
" is_club " : False ,
" is_club_rep " : False ,
" program " : " Math " ,
" terms " : [ " s2021 " ] ,
" mail_local_addresses " : [ " test_1@csclub.internal " ] ,
" forwarding_addresses " : [ ' test_1@uwaterloo.internal ' ] ,
" password " : " krb5 "
" mail_local_addresses " : [ " test1@csclub.internal " ] ,
" forwarding_addresses " : [ ' test1@uwaterloo.internal ' ] ,
" password " : " krb5 " ,
" shadowExpire " : None ,
} } ,
]
assert data == expected
# Two messages should have been sent: a welcome message to the new member,
# and an announcement to the ceo mailing list
assert len ( mock_mail_server . messages ) == 2
assert mock_mail_server . messages [ 0 ] [ ' to ' ] == ' test_ 1@csclub.internal '
assert mock_mail_server . messages [ 0 ] [ ' to ' ] == ' test1@csclub.internal '
assert mock_mail_server . messages [ 1 ] [ ' to ' ] == ' ceo@csclub.internal,ctdalek@csclub.internal '
mock_mail_server . messages . clear ( )
@ -198,7 +202,7 @@ def test_api_renew_user(cfg, client, create_user_result, ldap_conn):
def test_api_reset_password ( client , create_user_result ) :
uid = create_user_result [ ' uid ' ]
with patch . object ( utils , ' gen_password ' ) as gen_password_mock :
with patch . object ( ceod . utils , ' gen_password ' ) as gen_password_mock :
gen_password_mock . return_value = ' new_password '
status , data = client . post ( f ' /api/members/ { uid } /pwreset ' )
assert status == 200
@ -212,7 +216,7 @@ def test_api_reset_password(client, create_user_result):
def test_authz_check ( client , create_user_result ) :
# non-staff members may not create users
status , data = client . post ( ' /api/members ' , json = {
' uid ' : ' test_ 1 ' , ' cn ' : ' Test One ' , ' given_name ' : ' Test ' ,
' uid ' : ' test1 ' , ' cn ' : ' Test One ' , ' given_name ' : ' Test ' ,
' sn ' : ' One ' , ' terms ' : [ ' s2021 ' ] ,
} , principal = ' regular1 ' )
assert status == 403
@ -227,7 +231,56 @@ def test_authz_check(client, create_user_result):
# If we're syscom but we don't pass credentials, the request should fail
_ , data = client . post ( ' /api/members ' , json = {
' uid ' : ' test_ 1 ' , ' cn ' : ' Test One ' , ' given_name ' : ' Test ' ,
' uid ' : ' test1 ' , ' cn ' : ' Test One ' , ' given_name ' : ' Test ' ,
' sn ' : ' One ' , ' terms ' : [ ' s2021 ' ] ,
} , principal = ' ctdalek ' , delegate = False )
assert data [ - 1 ] [ ' status ' ] == ' aborted '
@pytest . mark . parametrize ( ' term_attr ' , [ ' terms ' , ' non_member_terms ' ] )
def test_expire ( client , new_user_gen , term_attr ) :
start_of_current_term = Term . current ( ) . to_datetime ( )
# test_date, should_expire
test_cases = [
# same term, membership is still valid
( start_of_current_term + datetime . timedelta ( days = 90 ) , False ) ,
# first month of next term, grace period is activated
( start_of_current_term + datetime . timedelta ( days = 130 ) , False ) ,
# second month of next term, membership is now invalid
( start_of_current_term + datetime . timedelta ( days = 160 ) , True ) ,
# next next term, membership is definitely invalid
( start_of_current_term + datetime . timedelta ( days = 250 ) , True ) ,
]
for test_date , should_expire in test_cases :
with new_user_gen ( ) as user_obj , \
patch . object ( ceo_common . utils , ' get_current_datetime ' ) as datetime_mock :
user = user_obj . to_dict ( )
uid = user [ ' uid ' ]
datetime_mock . return_value = test_date
assert user [ ' shadowExpire ' ] is None
status , data = client . post ( ' /api/members/expire?dry_run=yes ' )
assert status == 200
assert ( data == [ uid ] ) == should_expire
_ , user = client . get ( f ' /api/members/ { uid } ' )
assert user [ ' shadowExpire ' ] is None
status , data = client . post ( ' /api/members/expire ' )
assert status == 200
assert ( data == [ uid ] ) == should_expire
_ , user = client . get ( f ' /api/members/ { uid } ' )
assert ( user [ ' shadowExpire ' ] is not None ) == should_expire
if not should_expire :
continue
term = Term . from_datetime ( test_date )
status , _ = client . post ( f ' /api/members/ { uid } /renew ' , json = { term_attr : [ str ( term ) ] } )
assert status == 200
_ , user = client . get ( f ' /api/members/ { uid } ' )
assert user [ ' shadowExpire ' ] is None