LOC-24 Added tests for kick/ban functionality
LOC-24 Added tests for kick/ban functionality

Test 11 invites a user, has them join and then kicks them (before verifying in the database)
Test 12 has that user rejoin and then bans them (again verifying against the database)

--- a/tests/run_tests.py
+++ b/tests/run_tests.py
@@ -142,7 +142,8 @@
     
     test_results = []
     tests = ['test_one','test_two','test_three','test_four',
-             'test_five']
+             'test_five','test_six','test_seven','test_eight',
+             'test_nine','test_ten','test_eleven','test_twelve']
     x = 1
     for test in tests:
         print "Running %s " % (test,)
@@ -385,6 +386,404 @@
     
 
 
+def test_six(msg):
+    ''' Invite a user
+    '''
+    result = {'Test' : 'Invite a user','Result' : 'FAIL', 'Notes': '' }
+    isFatal = True
+    
+    n = msg.inviteUser('testuser')
+    if not n:
+        result['Notes'] = 'Could not invite testuser'
+        return [result,isFatal]
+    
+    if len(n) < 4:
+        result['Notes'] = 'Client returned too short response'
+        return [result,isFatal]
+        
+    # Otherwise, we've got details for a new user to be able to join
+    #
+    # Store them for a later test
+    
+    STORAGE['testuser'] = {
+        'room':n[0],
+        'pass':"%s:%s" % (n[1],n[2]),
+        'User':n[3]
+        }
+    
+    result['Result'] = "Pass"
+    return [result,isFatal]
+
+
+
+def test_seven(msg):
+    ''' Have the previously invited user join from a new client instance
+    '''
+    result = {'Test' : 'Join as Invited User','Result' : 'FAIL', 'Notes': '' }
+    isFatal = True
+    
+    usermsg = getClientInstance();
+    n = usermsg.joinRoom(STORAGE['testuser']['User'],STORAGE['testuser']['room'],STORAGE['testuser']['pass'])
+    
+    if not n:
+        result['Notes'] = 'Could not join'
+        return [result,isFatal]
+    
+    STORAGE['testuser']['clientInstance'] = usermsg
+    
+    CONN,CURSOR = opendb()
+    
+    # Check the DB to ensure we're now active
+    CURSOR.execute("SELECT * from users where username=? and active=1",(STORAGE['testuser']['User'],))
+    r = CURSOR.fetchone()
+    CONN.close()
+    
+    if not r:
+        result['Notes'] = 'Not Active in DB'
+        return [result,isFatal]
+    
+    # Check we've got a session token
+    if not msg.sesskey:
+        result['Notes'] = 'No Session Key'
+        return [result,isFatal]
+        
+    # Check the client has recorded what it needs to
+    if not msg.room:
+        result['Notes'] = 'Client forgot room'
+        return [result,isFatal]
+
+    if not msg.user:
+        result['Notes'] = 'Client forgot user'
+        return [result,isFatal]
+
+    if not msg.roompass:
+        result['Notes'] = 'Client forgot roompass'
+        return [result,isFatal]
+
+    if not msg.syskey:
+        result['Notes'] = 'No SYSTEM key'
+        return [result,isFatal]
+    
+    
+    result['Result'] = 'Pass'
+    return [result,isFatal]
+
+
+def test_eight(msg):
+    ''' Have the testuser send a message and ensure that the adminuser receives it
+    
+    We first call pollMsg to flush the message queue
+    '''
+    
+    result = {'Test' : 'Send a Message','Result' : 'FAIL', 'Notes': '' }
+    isFatal = False
+        
+    # Poll for messages to clear the queue
+    f = msg.pollForMessage()
+    
+    testpayload = 'The admin is a ....'
+    # Now send a message as test user
+    STORAGE['testuser']['clientInstance'].sendMsg(testpayload)
+    
+    # Now call pollMsg as admin to ensure we receive the message
+    received = msg.pollForMessage()
+
+    # Poll as testuser to clear the queue ready for future tests
+    f = STORAGE['testuser']['clientInstance'].pollForMessage()
+    
+    if len(received) < 1:
+        result['Notes'] = 'No messages received'
+        return [result,isFatal]
+    
+    if len(received[0]) < 2:
+        result['Notes'] = 'Malformed message returned'
+        return [result,isFatal]
+        
+    # Now check the payload
+    #
+    # We need to trim out the timestamp etc
+    r = received[0][1].split('>')
+    m = r[1].lstrip()
+    if testpayload != m:
+        result['Notes'] = 'Incorrect message received: (%s)v(%s)' % (testpayload,m)
+        return [result,isFatal]
+        
+    result['Result'] = 'Pass'
+    return [result,isFatal]
+
+
+
+def test_nine(msg):
+    ''' Try to maliciously invite SYSTEM (as a precursor to logging in as them)
+    
+    Essentially a regression test for LOC-5
+    
+    '''
+    
+    result = {'Test' : 'LOC-5 Try to invite SYSTEM','Result' : 'FAIL', 'Notes': '' }
+    isFatal = False
+        
+    # Poll for messages to clear the queue
+    f = msg.pollForMessage()
+    
+    # Now have the test user try to invite SYSTEM
+    n = STORAGE['testuser']['clientInstance'].inviteUser('SYSTEM')
+    if n:
+        result['Notes'] = 'Allowed to invite SYSTEM'
+        return [result,isFatal]
+    
+    # Now call pollMsg as admin to ensure we received the warning message
+    received = msg.pollForMessage()
+
+    # Poll as testuser to clear the queue ready for future tests
+    f = STORAGE['testuser']['clientInstance'].pollForMessage()
+    
+    if len(received) < 1:
+        result['Notes'] = 'No warning message received'
+        return [result,isFatal]
+    
+    if len(received[0]) < 2:
+        result['Notes'] = 'Malformed message returned'
+        return [result,isFatal]
+        
+    # Now check the payload
+    #
+    # We need to trim out the timestamp etc
+    r = received[0][1].split('>')
+    m = r[1].lstrip()
+    
+    expected = "ALERT: User %s tried to invite SYSTEM" % (STORAGE['testuser']['User'],)
+
+    if expected != m:
+        result['Notes'] = 'Unexpected message received: %s' % (m)
+        return [result,isFatal]
+        
+    result['Result'] = 'Pass'
+    return [result,isFatal]
+
+
+def test_ten(msg):
+    ''' Send a direct message and ensure it's received
+    
+    '''
+    
+    result = {'Test' : 'Send a Direct Message','Result' : 'FAIL', 'Notes': '' }
+    isFatal = False
+    
+    # Poll for messages to clear the queue
+    f = msg.pollForMessage()
+    f = STORAGE['testuser']['clientInstance'].pollForMessage()
+    
+    testpayload = 'Hi Hi'
+    
+    # Now send a direct message from test user to admin
+    n = STORAGE['testuser']['clientInstance'].sendDirectMsg(testpayload,'testadmin')
+    if not n:
+        result['Notes'] = 'Could not send direct message'
+        return [result,isFatal]
+    
+    # Poll as the admin user to ensure it was received
+    received = msg.pollForMessage()
+    
+    # Poll as testuser to clear the queue ready for future tests
+    f = STORAGE['testuser']['clientInstance'].pollForMessage()
+    
+    if len(received) < 1:
+        result['Notes'] = 'No messages received'
+        return [result,isFatal]
+    
+    if len(received[0]) < 2:
+        result['Notes'] = 'Malformed message returned'
+        return [result,isFatal]
+        
+    # Now check the payload
+    #
+    # We need to trim out the timestamp etc
+    r = received[0][1].split('>')
+    m = r[1].lstrip()
+    if testpayload != m:
+        result['Notes'] = 'Incorrect message received: (%s)v(%s)' % (testpayload,m)
+        return [result,isFatal]
+        
+    if "DM" not in r[0]:
+        result['Notes'] = 'Envelope not marked as DM: %s' % (r[0],)
+        return [result,isFatal]
+        
+    result['Result'] = 'Pass'
+    return [result,isFatal]
+    
+
+
+def test_eleven(msg):
+    ''' Invite a new user and then have admin kick them to ensure they're 
+    actually kicked out of the room
+    
+    '''
+    result = {'Test' : 'Invite and kick a user','Result' : 'FAIL', 'Notes': '' }
+    isFatal = True
+    
+    n = msg.inviteUser('testuser2')
+    if not n:
+        result['Notes'] = 'Could not invite testuser2'
+        return [result,isFatal]
+    
+    if len(n) < 4:
+        result['Notes'] = 'Client returned too short response'
+        return [result,isFatal]
+        
+    # Otherwise, we've got details for a new user to be able to join
+    #
+    # Store them for a later test
+    
+    STORAGE['testuser2'] = {
+        'room':n[0],
+        'pass':"%s:%s" % (n[1],n[2]),
+        'User':n[3]
+        }
+    
+    # Create a new instance so we can join as testuser2
+    usermsg = getClientInstance();
+    n = usermsg.joinRoom(STORAGE['testuser2']['User'],STORAGE['testuser2']['room'],STORAGE['testuser2']['pass'])
+    
+    if not n:
+        result['Notes'] = 'User could not join'
+        return [result,isFatal]
+    
+    STORAGE['testuser2']['clientInstance'] = usermsg
+    
+    # Now have the admin kick (but not ban) them
+    msg.kickUser('testuser2',False)
+    
+    
+    # Check that a failure message was written
+    CONN,CURSOR = opendb()
+    CURSOR.execute("SELECT msg FROM failuremsgs where username=?",(STORAGE['testuser2']['User'],))
+    r = CURSOR.fetchone()
+    CONN.close()
+    
+    if not r:
+        result['Notes'] = 'User not notified'
+        return [result,isFatal]  
+        
+    # Poll to receive the failure message and verify it's deleted
+    msgs = STORAGE['testuser2']['clientInstance'].pollForMessage()
+    
+    if len(msgs) < 1:
+        result['Notes'] = "User didn't receive notification"
+        return [result,isFatal]        
+    
+    CONN,CURSOR = opendb()
+    CURSOR.execute("SELECT msg FROM failuremsgs where username=?",(STORAGE['testuser2']['User'],))
+    r = CURSOR.fetchone()
+    CONN.close()
+    
+    if r:
+        result['Notes'] = 'Notification not purged on poll'
+        return [result,isFatal]  
+    
+    # Now check that their session was suspended
+    CONN,CURSOR = opendb()
+    CURSOR.execute("SELECT username FROM users where username=? and active=1",(STORAGE['testuser2']['User'],))
+    r = CURSOR.fetchone()
+    CONN.close()
+    
+    if r:
+        result['Notes'] = 'User still considered active in room'
+        return [result,isFatal]         
+    
+    # Check if their session still exists
+    CONN,CURSOR = opendb()
+    CURSOR.execute("SELECT username FROM sessions where username=?",(STORAGE['testuser2']['User'],))
+    r = CURSOR.fetchone()
+    CONN.close()    
+    if r:
+        result['Notes'] = 'User still has active session'
+        return [result,isFatal]        
+    
+    # Otherwise, looks good
+    result['Result'] = "Pass"
+    return [result,isFatal]
+
+
+def test_twelve(msg):
+    ''' Rejoin as the previously invited user, and then ban them
+    
+    
+    '''
+    result = {'Test' : 'Ban a user','Result' : 'FAIL', 'Notes': '' }
+    isFatal = True
+    
+    # Flush the failedmessage queue
+    f = STORAGE['testuser2']['clientInstance'].pollForMessage()
+    
+    # Re-join as testuser2
+    n = STORAGE['testuser2']['clientInstance'].joinRoom(STORAGE['testuser2']['User'],
+                                                        STORAGE['testuser2']['room'],STORAGE['testuser2']['pass'])
+    
+    if not n:
+        result['Notes'] = 'TestUser2 could not join'
+        return [result,isFatal]
+    
+    # Now have the admin ban them
+    msg.kickUser('testuser2',True)
+    
+    
+    # Check that a failure message was written
+    CONN,CURSOR = opendb()
+    CURSOR.execute("SELECT msg FROM failuremsgs where username=?",(STORAGE['testuser2']['User'],))
+    r = CURSOR.fetchone()
+    CONN.close()
+    
+    if not r:
+        result['Notes'] = 'User not notified'
+        return [result,isFatal]  
+    
+    # Poll to receive the failure message and verify it's deleted
+    msgs = STORAGE['testuser2']['clientInstance'].pollForMessage()
+    
+    if len(msgs) < 1:
+        result['Notes'] = "User didn't receive notification"
+        return [result,isFatal]        
+    
+    CONN,CURSOR = opendb()
+    CURSOR.execute("SELECT msg FROM failuremsgs where username=?",(STORAGE['testuser2']['User'],))
+    r = CURSOR.fetchone()
+    CONN.close()
+    
+    if r:
+        result['Notes'] = 'Notification not purged on poll'
+        return [result,isFatal]  
+   
+    # Now check that their session was suspended
+    CONN,CURSOR = opendb()
+    CURSOR.execute("SELECT username FROM users where username=?",(STORAGE['testuser2']['User'],))
+    r = CURSOR.fetchone()
+    CONN.close()
+    
+    if r:
+        result['Notes'] = 'User still exists for room'
+        return [result,isFatal]         
+    
+    # Check if their session still exists
+    CONN,CURSOR = opendb()
+    CURSOR.execute("SELECT username FROM sessions where username=?",(STORAGE['testuser2']['User'],))
+    r = CURSOR.fetchone()
+    CONN.close()    
+    if r:
+        result['Notes'] = 'User still has active session'
+        return [result,isFatal]        
+    
+    # We don't need this any more
+    del STORAGE['testuser2']
+    
+    # Otherwise, looks good
+    result['Result'] = "Pass"
+    return [result,isFatal]
+
+
+    
+
+
 if __name__ == '__main__':
     # Start the server
     proc1 = restartServer(False)