2019-06-30 20:14:03 +00:00
__filename__ = " tests.py "
__author__ = " Bob Mottram "
__license__ = " AGPL3+ "
__version__ = " 0.0.1 "
__maintainer__ = " Bob Mottram "
__email__ = " bob@freedombone.net "
__status__ = " Production "
import base64
import time
2019-07-04 20:36:12 +00:00
import os , os . path
2019-06-30 21:20:02 +00:00
import shutil
2019-06-30 20:14:03 +00:00
from person import createPerson
from Crypto . Hash import SHA256
from httpsig import signPostHeaders
from httpsig import verifyPostHeaders
from cache import storePersonInCache
from cache import getPersonFromCache
from threads import threadWithTrace
2019-06-30 21:20:02 +00:00
from daemon import runDaemon
from session import createSession
from posts import deleteAllPosts
from posts import createPublicPost
2019-06-30 22:56:37 +00:00
from posts import sendPost
2019-07-03 10:09:24 +00:00
from posts import archivePosts
2019-07-01 11:09:09 +00:00
from follow import clearFollows
from follow import clearFollowers
2019-06-30 21:20:02 +00:00
from follow import followPerson
from follow import followerOfPerson
2019-07-01 11:09:09 +00:00
from follow import unfollowPerson
from follow import unfollowerOfPerson
2019-07-05 12:35:29 +00:00
from follow import getFollowersOfPerson
2019-07-03 10:04:23 +00:00
from person import createPerson
from person import setPreferredNickname
from person import setBio
2019-07-03 18:24:44 +00:00
from auth import createBasicAuthHeader
from auth import authorizeBasic
from auth import storeBasicCredentials
2019-06-30 20:14:03 +00:00
2019-06-30 21:27:25 +00:00
testServerAliceRunning = False
testServerBobRunning = False
2019-06-30 20:14:03 +00:00
def testHttpsigBase ( withDigest ) :
print ( ' testHttpsig( ' + str ( withDigest ) + ' ) ' )
2019-07-03 09:40:27 +00:00
nickname = ' socrates '
2019-06-30 20:14:03 +00:00
domain = ' argumentative.social '
2019-07-03 19:00:03 +00:00
httpPrefix = ' https '
2019-07-01 09:31:02 +00:00
port = 5576
2019-06-30 22:56:37 +00:00
baseDir = os . getcwd ( )
2019-07-04 19:09:48 +00:00
password = ' SuperSecretPassword '
privateKeyPem , publicKeyPem , person , wfEndpoint = createPerson ( baseDir , nickname , domain , port , httpPrefix , False , password )
2019-07-01 09:31:02 +00:00
messageBodyJsonStr = ' { " a key " : " a value " , " another key " : " A string " } '
headersDomain = domain
if port != 80 and port != 443 :
headersDomain = domain + ' : ' + str ( port )
2019-06-30 20:14:03 +00:00
if not withDigest :
2019-07-01 09:31:02 +00:00
headers = { ' host ' : headersDomain }
2019-06-30 20:14:03 +00:00
else :
2019-07-01 09:31:02 +00:00
bodyDigest = base64 . b64encode ( SHA256 . new ( messageBodyJsonStr . encode ( ) ) . digest ( ) )
headers = { ' host ' : headersDomain , ' digest ' : f ' SHA-256= { bodyDigest } ' }
2019-06-30 20:14:03 +00:00
path = ' /inbox '
2019-07-03 19:00:03 +00:00
signatureHeader = signPostHeaders ( privateKeyPem , nickname , domain , port , path , httpPrefix , None )
2019-06-30 20:14:03 +00:00
headers [ ' signature ' ] = signatureHeader
2019-07-03 19:00:03 +00:00
assert verifyPostHeaders ( httpPrefix , publicKeyPem , headers , ' /inbox ' , False , messageBodyJsonStr )
assert verifyPostHeaders ( httpPrefix , publicKeyPem , headers , ' /parambulator/inbox ' , False , messageBodyJsonStr ) == False
assert verifyPostHeaders ( httpPrefix , publicKeyPem , headers , ' /inbox ' , True , messageBodyJsonStr ) == False
2019-06-30 20:14:03 +00:00
if not withDigest :
# fake domain
headers = { ' host ' : ' bogon.domain ' }
else :
# correct domain but fake message
2019-07-01 09:31:02 +00:00
messageBodyJsonStr = ' { " a key " : " a value " , " another key " : " Fake GNUs " } '
bodyDigest = base64 . b64encode ( SHA256 . new ( messageBodyJsonStr . encode ( ) ) . digest ( ) )
2019-06-30 20:14:03 +00:00
headers = { ' host ' : domain , ' digest ' : f ' SHA-256= { bodyDigest } ' }
headers [ ' signature ' ] = signatureHeader
2019-07-03 19:00:03 +00:00
assert verifyPostHeaders ( httpPrefix , publicKeyPem , headers , ' /inbox ' , True , messageBodyJsonStr ) == False
2019-06-30 20:14:03 +00:00
def testHttpsig ( ) :
testHttpsigBase ( False )
testHttpsigBase ( True )
def testCache ( ) :
print ( ' testCache ' )
personUrl = " cat@cardboard.box "
personJson = { " id " : 123456 , " test " : " This is a test " }
2019-07-01 14:30:48 +00:00
personCache = { }
storePersonInCache ( personUrl , personJson , personCache )
result = getPersonFromCache ( personUrl , personCache )
2019-06-30 20:14:03 +00:00
assert result [ ' id ' ] == 123456
assert result [ ' test ' ] == ' This is a test '
def testThreadsFunction ( param : str ) :
for i in range ( 10000 ) :
time . sleep ( 2 )
def testThreads ( ) :
print ( ' testThreads ' )
thr = threadWithTrace ( target = testThreadsFunction , args = ( ' test ' , ) , daemon = True )
thr . start ( )
assert thr . isAlive ( ) == True
time . sleep ( 1 )
thr . kill ( )
thr . join ( )
assert thr . isAlive ( ) == False
2019-06-30 21:20:02 +00:00
2019-07-01 21:01:43 +00:00
def createServerAlice ( path : str , domain : str , port : int , federationList : [ ] ) :
2019-06-30 21:20:02 +00:00
print ( ' Creating test server: Alice on port ' + str ( port ) )
if os . path . isdir ( path ) :
shutil . rmtree ( path )
os . mkdir ( path )
os . chdir ( path )
2019-07-03 09:40:27 +00:00
nickname = ' alice '
2019-07-04 14:36:29 +00:00
httpPrefix = ' http '
2019-06-30 21:20:02 +00:00
useTor = False
2019-07-03 15:10:18 +00:00
clientToServer = False
2019-07-04 19:09:48 +00:00
password = ' alicepass '
privateKeyPem , publicKeyPem , person , wfEndpoint = createPerson ( path , nickname , domain , port , httpPrefix , True , password )
2019-07-04 16:24:23 +00:00
deleteAllPosts ( path , nickname , domain , ' inbox ' )
deleteAllPosts ( path , nickname , domain , ' outbox ' )
2019-07-03 09:40:27 +00:00
followPerson ( path , nickname , domain , ' bob ' , ' 127.0.0.100:61936 ' , federationList )
followerOfPerson ( path , nickname , domain , ' bob ' , ' 127.0.0.100:61936 ' , federationList )
2019-07-03 19:00:03 +00:00
createPublicPost ( path , nickname , domain , port , httpPrefix , " No wise fish would go anywhere without a porpoise " , False , True , clientToServer )
createPublicPost ( path , nickname , domain , port , httpPrefix , " Curiouser and curiouser! " , False , True , clientToServer )
createPublicPost ( path , nickname , domain , port , httpPrefix , " In the gardens of memory, in the palace of dreams, that is where you and I shall meet " , False , True , clientToServer )
2019-06-30 21:27:25 +00:00
global testServerAliceRunning
testServerAliceRunning = True
2019-06-30 21:20:02 +00:00
print ( ' Server running: Alice ' )
2019-07-04 14:36:29 +00:00
runDaemon ( path , domain , port , httpPrefix , federationList , useTor , True )
2019-06-30 21:20:02 +00:00
2019-07-01 21:01:43 +00:00
def createServerBob ( path : str , domain : str , port : int , federationList : [ ] ) :
2019-06-30 21:20:02 +00:00
print ( ' Creating test server: Bob on port ' + str ( port ) )
if os . path . isdir ( path ) :
shutil . rmtree ( path )
os . mkdir ( path )
os . chdir ( path )
2019-07-03 09:40:27 +00:00
nickname = ' bob '
2019-07-03 19:00:03 +00:00
httpPrefix = ' http '
2019-06-30 21:20:02 +00:00
useTor = False
2019-07-03 15:10:18 +00:00
clientToServer = False
2019-07-04 19:09:48 +00:00
password = ' bobpass '
privateKeyPem , publicKeyPem , person , wfEndpoint = createPerson ( path , nickname , domain , port , httpPrefix , True , password )
2019-07-04 16:24:23 +00:00
deleteAllPosts ( path , nickname , domain , ' inbox ' )
deleteAllPosts ( path , nickname , domain , ' outbox ' )
2019-07-03 09:40:27 +00:00
followPerson ( path , nickname , domain , ' alice ' , ' 127.0.0.50:61935 ' , federationList )
followerOfPerson ( path , nickname , domain , ' alice ' , ' 127.0.0.50:61935 ' , federationList )
2019-07-03 19:00:03 +00:00
createPublicPost ( path , nickname , domain , port , httpPrefix , " It ' s your life, live it your way. " , False , True , clientToServer )
createPublicPost ( path , nickname , domain , port , httpPrefix , " One of the things I ' ve realised is that I am very simple " , False , True , clientToServer )
createPublicPost ( path , nickname , domain , port , httpPrefix , " Quantum physics is a bit of a passion of mine " , False , True , clientToServer )
2019-06-30 21:27:25 +00:00
global testServerBobRunning
testServerBobRunning = True
2019-06-30 21:20:02 +00:00
print ( ' Server running: Bob ' )
2019-07-04 14:36:29 +00:00
runDaemon ( path , domain , port , httpPrefix , federationList , useTor , True )
2019-06-30 21:20:02 +00:00
def testPostMessageBetweenServers ( ) :
print ( ' Testing sending message from one server to the inbox of another ' )
2019-06-30 21:27:25 +00:00
global testServerAliceRunning
global testServerBobRunning
testServerAliceRunning = False
testServerBobRunning = False
2019-07-03 19:00:03 +00:00
httpPrefix = ' http '
2019-06-30 22:56:37 +00:00
useTor = False
2019-07-02 09:25:29 +00:00
federationList = [ ' 127.0.0.50 ' , ' 127.0.0.100 ' ]
2019-06-30 22:56:37 +00:00
2019-06-30 21:20:02 +00:00
baseDir = os . getcwd ( )
if not os . path . isdir ( baseDir + ' /.tests ' ) :
os . mkdir ( baseDir + ' /.tests ' )
# create the servers
2019-06-30 22:56:37 +00:00
aliceDir = baseDir + ' /.tests/alice '
2019-07-02 09:25:29 +00:00
aliceDomain = ' 127.0.0.50 '
2019-06-30 22:56:37 +00:00
alicePort = 61935
2019-07-01 21:01:43 +00:00
thrAlice = threadWithTrace ( target = createServerAlice , args = ( aliceDir , aliceDomain , alicePort , federationList ) , daemon = True )
2019-06-30 21:20:02 +00:00
2019-06-30 22:56:37 +00:00
bobDir = baseDir + ' /.tests/bob '
2019-07-02 09:25:29 +00:00
bobDomain = ' 127.0.0.100 '
2019-06-30 22:56:37 +00:00
bobPort = 61936
2019-07-01 21:01:43 +00:00
thrBob = threadWithTrace ( target = createServerBob , args = ( bobDir , bobDomain , bobPort , federationList ) , daemon = True )
thrAlice . start ( )
2019-06-30 21:20:02 +00:00
thrBob . start ( )
2019-07-01 21:01:43 +00:00
assert thrAlice . isAlive ( ) == True
2019-06-30 21:20:02 +00:00
assert thrBob . isAlive ( ) == True
2019-06-30 21:27:25 +00:00
# wait for both servers to be running
while not ( testServerAliceRunning and testServerBobRunning ) :
time . sleep ( 1 )
2019-07-04 20:25:19 +00:00
time . sleep ( 1 )
2019-06-30 21:20:02 +00:00
2019-06-30 22:56:37 +00:00
print ( ' Alice sends to Bob ' )
os . chdir ( aliceDir )
2019-07-02 09:25:29 +00:00
sessionAlice = createSession ( aliceDomain , alicePort , useTor )
2019-06-30 22:56:37 +00:00
inReplyTo = None
inReplyToAtomUri = None
subject = None
aliceSendThreads = [ ]
alicePostLog = [ ]
2019-07-01 12:51:55 +00:00
followersOnly = False
saveToFile = True
2019-07-03 15:10:18 +00:00
clientToServer = False
2019-07-01 12:51:55 +00:00
ccUrl = None
2019-07-01 14:30:48 +00:00
alicePersonCache = { }
aliceCachedWebfingers = { }
2019-07-03 19:00:03 +00:00
sendResult = sendPost ( sessionAlice , aliceDir , ' alice ' , aliceDomain , alicePort , ' bob ' , bobDomain , bobPort , ccUrl , httpPrefix , ' Why is a mouse when it spins? ' , followersOnly , saveToFile , clientToServer , federationList , aliceSendThreads , alicePostLog , aliceCachedWebfingers , alicePersonCache , inReplyTo , inReplyToAtomUri , subject )
2019-06-30 22:56:37 +00:00
print ( ' sendResult: ' + str ( sendResult ) )
2019-07-04 20:36:12 +00:00
queuePath = bobDir + ' /accounts/bob@ ' + bobDomain + ' /queue '
inboxPath = bobDir + ' /accounts/bob@ ' + bobDomain + ' /inbox '
for i in range ( 10 ) :
if os . path . isdir ( inboxPath ) :
if len ( [ name for name in os . listdir ( inboxPath ) if os . path . isfile ( os . path . join ( inboxPath , name ) ) ] ) > 0 :
break
2019-07-01 21:01:43 +00:00
time . sleep ( 1 )
2019-06-30 22:56:37 +00:00
2019-06-30 21:20:02 +00:00
# stop the servers
thrAlice . kill ( )
thrAlice . join ( )
assert thrAlice . isAlive ( ) == False
thrBob . kill ( )
thrBob . join ( )
assert thrBob . isAlive ( ) == False
2019-07-04 20:36:12 +00:00
# inbox item created
assert len ( [ name for name in os . listdir ( inboxPath ) if os . path . isfile ( os . path . join ( inboxPath , name ) ) ] ) == 1
# queue item removed
assert len ( [ name for name in os . listdir ( queuePath ) if os . path . isfile ( os . path . join ( queuePath , name ) ) ] ) == 0
2019-07-05 12:35:29 +00:00
os . chdir ( baseDir )
shutil . rmtree ( aliceDir )
shutil . rmtree ( bobDir )
def testFollowersOfPerson ( ) :
print ( ' testFollowersOfPerson ' )
currDir = os . getcwd ( )
nickname = ' mxpop '
domain = ' diva.domain '
password = ' birb '
port = 80
httpPrefix = ' https '
federationList = [ ]
baseDir = currDir + ' /.tests_followersofperson '
if os . path . isdir ( baseDir ) :
shutil . rmtree ( baseDir )
os . mkdir ( baseDir )
os . chdir ( baseDir )
createPerson ( baseDir , nickname , domain , port , httpPrefix , True , password )
createPerson ( baseDir , ' maxboardroom ' , domain , port , httpPrefix , True , password )
createPerson ( baseDir , ' ultrapancake ' , domain , port , httpPrefix , True , password )
createPerson ( baseDir , ' drokk ' , domain , port , httpPrefix , True , password )
createPerson ( baseDir , ' sausagedog ' , domain , port , httpPrefix , True , password )
clearFollows ( baseDir , nickname , domain )
followPerson ( baseDir , nickname , domain , ' maxboardroom ' , domain , federationList )
followPerson ( baseDir , ' drokk ' , domain , ' ultrapancake ' , domain , federationList )
# deliberate duplication
followPerson ( baseDir , ' drokk ' , domain , ' ultrapancake ' , domain , federationList )
followPerson ( baseDir , ' sausagedog ' , domain , ' ultrapancake ' , domain , federationList )
followPerson ( baseDir , nickname , domain , ' ultrapancake ' , domain , federationList )
followPerson ( baseDir , nickname , domain , ' someother ' , ' randodomain.net ' , federationList )
followList = getFollowersOfPerson ( baseDir , ' ultrapancake ' , domain )
assert len ( followList ) == 3
assert ' mxpop@ ' + domain in followList
assert ' drokk@ ' + domain in followList
assert ' sausagedog@ ' + domain in followList
os . chdir ( currDir )
shutil . rmtree ( baseDir )
2019-07-03 09:24:55 +00:00
def testFollows ( ) :
2019-07-03 10:04:23 +00:00
print ( ' testFollows ' )
2019-07-03 09:24:55 +00:00
currDir = os . getcwd ( )
2019-07-03 09:40:27 +00:00
nickname = ' test529 '
2019-07-03 09:24:55 +00:00
domain = ' testdomain.com '
2019-07-04 19:09:48 +00:00
password = ' mypass '
2019-07-03 09:24:55 +00:00
port = 80
2019-07-03 19:00:03 +00:00
httpPrefix = ' https '
2019-07-03 09:24:55 +00:00
federationList = [ ' wild.com ' , ' mesh.com ' ]
baseDir = currDir + ' /.tests_testfollows '
if os . path . isdir ( baseDir ) :
shutil . rmtree ( baseDir )
os . mkdir ( baseDir )
2019-07-04 19:09:48 +00:00
os . chdir ( baseDir )
createPerson ( baseDir , nickname , domain , port , httpPrefix , True , password )
2019-07-03 09:24:55 +00:00
2019-07-03 09:40:27 +00:00
clearFollows ( baseDir , nickname , domain )
followPerson ( baseDir , nickname , domain , ' badger ' , ' wild.com ' , federationList )
followPerson ( baseDir , nickname , domain , ' squirrel ' , ' secret.com ' , federationList )
followPerson ( baseDir , nickname , domain , ' rodent ' , ' drainpipe.com ' , federationList )
followPerson ( baseDir , nickname , domain , ' batman ' , ' mesh.com ' , federationList )
followPerson ( baseDir , nickname , domain , ' giraffe ' , ' trees.com ' , federationList )
2019-07-03 09:24:55 +00:00
2019-07-03 09:40:27 +00:00
f = open ( baseDir + ' /accounts/ ' + nickname + ' @ ' + domain + ' /following.txt ' , " r " )
2019-07-03 09:33:28 +00:00
domainFound = False
2019-07-03 09:24:55 +00:00
for followingDomain in f :
testDomain = followingDomain . split ( ' @ ' ) [ 1 ] . replace ( ' \n ' , ' ' )
2019-07-03 09:33:28 +00:00
if testDomain == ' mesh.com ' :
domainFound = True
2019-07-03 09:24:55 +00:00
if testDomain not in federationList :
print ( testDomain )
assert ( False )
2019-07-03 09:33:28 +00:00
assert ( domainFound )
2019-07-03 09:40:27 +00:00
unfollowPerson ( baseDir , nickname , domain , ' batman ' , ' mesh.com ' )
2019-07-03 09:33:28 +00:00
domainFound = False
for followingDomain in f :
testDomain = followingDomain . split ( ' @ ' ) [ 1 ] . replace ( ' \n ' , ' ' )
if testDomain == ' mesh.com ' :
domainFound = True
assert ( domainFound == False )
2019-07-03 09:40:27 +00:00
clearFollowers ( baseDir , nickname , domain )
followerOfPerson ( baseDir , nickname , domain , ' badger ' , ' wild.com ' , federationList )
followerOfPerson ( baseDir , nickname , domain , ' squirrel ' , ' secret.com ' , federationList )
followerOfPerson ( baseDir , nickname , domain , ' rodent ' , ' drainpipe.com ' , federationList )
followerOfPerson ( baseDir , nickname , domain , ' batman ' , ' mesh.com ' , federationList )
followerOfPerson ( baseDir , nickname , domain , ' giraffe ' , ' trees.com ' , federationList )
2019-07-03 09:24:55 +00:00
2019-07-03 09:40:27 +00:00
f = open ( baseDir + ' /accounts/ ' + nickname + ' @ ' + domain + ' /followers.txt ' , " r " )
2019-07-03 09:24:55 +00:00
for followerDomain in f :
testDomain = followerDomain . split ( ' @ ' ) [ 1 ] . replace ( ' \n ' , ' ' )
if testDomain not in federationList :
print ( testDomain )
assert ( False )
os . chdir ( currDir )
shutil . rmtree ( baseDir )
2019-07-03 10:04:23 +00:00
def testCreatePerson ( ) :
print ( ' testCreatePerson ' )
currDir = os . getcwd ( )
nickname = ' test382 '
domain = ' badgerdomain.com '
2019-07-04 19:09:48 +00:00
password = ' mypass '
2019-07-03 10:04:23 +00:00
port = 80
2019-07-03 19:00:03 +00:00
httpPrefix = ' https '
2019-07-03 15:10:18 +00:00
clientToServer = False
2019-07-03 10:04:23 +00:00
baseDir = currDir + ' /.tests_createperson '
if os . path . isdir ( baseDir ) :
shutil . rmtree ( baseDir )
os . mkdir ( baseDir )
os . chdir ( baseDir )
2019-07-03 09:24:55 +00:00
2019-07-04 19:09:48 +00:00
privateKeyPem , publicKeyPem , person , wfEndpoint = createPerson ( baseDir , nickname , domain , port , httpPrefix , True , password )
assert os . path . isfile ( baseDir + ' /accounts/passwords ' )
2019-07-04 16:24:23 +00:00
deleteAllPosts ( baseDir , nickname , domain , ' inbox ' )
deleteAllPosts ( baseDir , nickname , domain , ' outbox ' )
2019-07-03 10:04:23 +00:00
setPreferredNickname ( baseDir , nickname , domain , ' badger ' )
setBio ( baseDir , nickname , domain , ' Randomly roaming in your backyard ' )
2019-07-04 16:24:23 +00:00
archivePosts ( nickname , domain , baseDir , ' inbox ' , 4 )
archivePosts ( nickname , domain , baseDir , ' outbox ' , 4 )
2019-07-03 19:00:03 +00:00
createPublicPost ( baseDir , nickname , domain , port , httpPrefix , " G ' day world! " , False , True , clientToServer , None , None , ' Not suitable for Vogons ' )
2019-07-03 10:04:23 +00:00
os . chdir ( currDir )
shutil . rmtree ( baseDir )
2019-07-03 18:24:44 +00:00
def testAuthentication ( ) :
print ( ' testAuthentication ' )
currDir = os . getcwd ( )
nickname = ' test8743 '
password = ' SuperSecretPassword12345 '
baseDir = currDir + ' /.tests_authentication '
if os . path . isdir ( baseDir ) :
shutil . rmtree ( baseDir )
os . mkdir ( baseDir )
os . chdir ( baseDir )
assert storeBasicCredentials ( baseDir , ' othernick ' , ' otherpass ' )
assert storeBasicCredentials ( baseDir , ' bad:nick ' , ' otherpass ' ) == False
assert storeBasicCredentials ( baseDir , ' badnick ' , ' otherpa:ss ' ) == False
assert storeBasicCredentials ( baseDir , nickname , password )
authHeader = createBasicAuthHeader ( nickname , password )
2019-07-04 08:56:15 +00:00
assert authorizeBasic ( baseDir , ' /users/ ' + nickname + ' /inbox ' , authHeader , False )
assert authorizeBasic ( baseDir , ' /users/ ' + nickname , authHeader , False ) == False
assert authorizeBasic ( baseDir , ' /users/othernick/inbox ' , authHeader , False ) == False
2019-07-03 18:24:44 +00:00
authHeader = createBasicAuthHeader ( nickname , password + ' 1 ' )
2019-07-04 08:56:15 +00:00
assert authorizeBasic ( baseDir , ' /users/ ' + nickname + ' /inbox ' , authHeader , False ) == False
2019-07-03 18:24:44 +00:00
2019-07-03 19:13:23 +00:00
password = ' someOtherPassword '
assert storeBasicCredentials ( baseDir , nickname , password )
authHeader = createBasicAuthHeader ( nickname , password )
2019-07-04 08:56:15 +00:00
assert authorizeBasic ( baseDir , ' /users/ ' + nickname + ' /inbox ' , authHeader , False )
2019-07-03 19:13:23 +00:00
2019-07-03 18:24:44 +00:00
os . chdir ( currDir )
shutil . rmtree ( baseDir )
2019-06-30 21:20:02 +00:00
def runAllTests ( ) :
print ( ' Running tests... ' )
testHttpsig ( )
testCache ( )
testThreads ( )
2019-07-03 10:04:23 +00:00
testCreatePerson ( )
2019-07-03 18:24:44 +00:00
testAuthentication ( )
2019-07-05 12:35:29 +00:00
testFollowersOfPerson ( )
testFollows ( )
2019-07-03 18:24:44 +00:00
print ( ' Tests succeeded \n ' )