tests.py 62 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600
  1. __filename__ = "tests.py"
  2. __author__ = "Bob Mottram"
  3. __license__ = "AGPL3+"
  4. __version__ = "1.0.0"
  5. __maintainer__ = "Bob Mottram"
  6. __email__ = "bob@freedombone.net"
  7. __status__ = "Production"
  8. import base64
  9. import time
  10. import os, os.path
  11. import shutil
  12. import commentjson
  13. import json
  14. from time import gmtime, strftime
  15. from pprint import pprint
  16. from person import createPerson
  17. from Crypto.Hash import SHA256
  18. from httpsig import signPostHeaders
  19. from httpsig import verifyPostHeaders
  20. from httpsig import messageContentDigest
  21. from cache import storePersonInCache
  22. from cache import getPersonFromCache
  23. from threads import threadWithTrace
  24. from daemon import runDaemon
  25. from session import createSession
  26. from posts import deleteAllPosts
  27. from posts import createPublicPost
  28. from posts import sendPost
  29. from posts import archivePosts
  30. from posts import noOfFollowersOnDomain
  31. from posts import groupFollowersByDomain
  32. from posts import sendCapabilitiesUpdate
  33. from posts import archivePostsForPerson
  34. from posts import sendPostViaServer
  35. from follow import clearFollows
  36. from follow import clearFollowers
  37. from follow import sendFollowRequestViaServer
  38. from follow import sendUnfollowRequestViaServer
  39. from utils import followPerson
  40. from utils import getNicknameFromActor
  41. from utils import getDomainFromActor
  42. from utils import copytree
  43. from utils import getStatusNumber
  44. from follow import followerOfPerson
  45. from follow import unfollowPerson
  46. from follow import unfollowerOfPerson
  47. from follow import getFollowersOfPerson
  48. from follow import sendFollowRequest
  49. from person import createPerson
  50. from person import setDisplayNickname
  51. from person import setBio
  52. from skills import setSkillLevel
  53. from roles import setRole
  54. from roles import getRoles
  55. from roles import outboxDelegate
  56. from auth import createBasicAuthHeader
  57. from auth import authorizeBasic
  58. from auth import storeBasicCredentials
  59. from like import likePost
  60. from like import sendLikeViaServer
  61. from announce import announcePublic
  62. from announce import sendAnnounceViaServer
  63. from media import getMediaPath
  64. from media import getAttachmentMediaType
  65. from delete import sendDeleteViaServer
  66. from inbox import validInbox
  67. from inbox import validInboxFilenames
  68. from content import addWebLinks
  69. from content import replaceEmojiFromTags
  70. from content import addHtmlTags
  71. testServerAliceRunning = False
  72. testServerBobRunning = False
  73. testServerEveRunning = False
  74. def testHttpsigBase(withDigest):
  75. print('testHttpsig(' + str(withDigest) + ')')
  76. baseDir=os.getcwd()
  77. path=baseDir+'/.testHttpsigBase'
  78. if os.path.isdir(path):
  79. shutil.rmtree(path)
  80. os.mkdir(path)
  81. os.chdir(path)
  82. contentType='application/activity+json'
  83. nickname='socrates'
  84. domain='argumentative.social'
  85. httpPrefix='https'
  86. port=5576
  87. password='SuperSecretPassword'
  88. privateKeyPem,publicKeyPem,person,wfEndpoint= \
  89. createPerson(path,nickname,domain,port,httpPrefix,False,password)
  90. assert privateKeyPem
  91. messageBodyJson = {"a key": "a value", "another key": "A string","yet another key": "Another string"}
  92. messageBodyJsonStr=json.dumps(messageBodyJson)
  93. headersDomain=domain
  94. if port:
  95. if port!=80 and port !=443:
  96. if ':' not in domain:
  97. headersDomain=domain+':'+str(port)
  98. dateStr=strftime("%a, %d %b %Y %H:%M:%S %Z", gmtime())
  99. boxpath='/inbox'
  100. if not withDigest:
  101. headers = {'host': headersDomain,'date': dateStr,'content-type': 'application/json'}
  102. signatureHeader = \
  103. signPostHeaders(dateStr,privateKeyPem, nickname, \
  104. domain, port, \
  105. domain, port, \
  106. boxpath, httpPrefix, None)
  107. else:
  108. bodyDigest = messageContentDigest(messageBodyJsonStr)
  109. headers = {'host': headersDomain,'date': dateStr,'digest': f'SHA-256={bodyDigest}','content-type': contentType}
  110. signatureHeader = \
  111. signPostHeaders(dateStr,privateKeyPem, nickname, \
  112. domain, port, \
  113. domain, port, \
  114. boxpath, httpPrefix, messageBodyJsonStr)
  115. headers['signature'] = signatureHeader
  116. assert verifyPostHeaders(httpPrefix,publicKeyPem,headers, \
  117. boxpath,False,None, \
  118. messageBodyJsonStr)
  119. assert verifyPostHeaders(httpPrefix,publicKeyPem,headers, \
  120. '/parambulator'+boxpath,False,None, \
  121. messageBodyJsonStr) == False
  122. assert verifyPostHeaders(httpPrefix,publicKeyPem,headers, \
  123. boxpath,True,None, \
  124. messageBodyJsonStr) == False
  125. if not withDigest:
  126. # fake domain
  127. headers = {'host': 'bogon.domain','date': dateStr,'content-type': 'application/json'}
  128. else:
  129. # correct domain but fake message
  130. messageBodyJsonStr = '{"a key": "a value", "another key": "Fake GNUs", "yet another key": "More Fake GNUs"}'
  131. bodyDigest = messageContentDigest(messageBodyJsonStr)
  132. headers = {'host': domain,'date': dateStr,'digest': f'SHA-256={bodyDigest}','content-type': contentType}
  133. headers['signature'] = signatureHeader
  134. assert verifyPostHeaders(httpPrefix,publicKeyPem,headers, \
  135. boxpath,True,None, \
  136. messageBodyJsonStr) == False
  137. os.chdir(baseDir)
  138. shutil.rmtree(path)
  139. def testHttpsig():
  140. testHttpsigBase(True)
  141. testHttpsigBase(False)
  142. def testCache():
  143. print('testCache')
  144. personUrl="cat@cardboard.box"
  145. personJson={ "id": 123456, "test": "This is a test" }
  146. personCache={}
  147. storePersonInCache(None,personUrl,personJson,personCache)
  148. result=getPersonFromCache(None,personUrl,personCache)
  149. assert result['id']==123456
  150. assert result['test']=='This is a test'
  151. def testThreadsFunction(param: str):
  152. for i in range(10000):
  153. time.sleep(2)
  154. def testThreads():
  155. print('testThreads')
  156. thr = threadWithTrace(target=testThreadsFunction,args=('test',),daemon=True)
  157. thr.start()
  158. assert thr.isAlive()==True
  159. time.sleep(1)
  160. thr.kill()
  161. thr.join()
  162. assert thr.isAlive()==False
  163. def createServerAlice(path: str,domain: str,port: int,federationList: [], \
  164. hasFollows: bool,hasPosts :bool,ocapAlways: bool):
  165. print('Creating test server: Alice on port '+str(port))
  166. if os.path.isdir(path):
  167. shutil.rmtree(path)
  168. os.mkdir(path)
  169. os.chdir(path)
  170. nickname='alice'
  171. httpPrefix='http'
  172. useTor=False
  173. password='alicepass'
  174. noreply=False
  175. nolike=False
  176. nopics=False
  177. noannounce=False
  178. cw=False
  179. useBlurhash=True
  180. maxReplies=64
  181. domainMaxPostsPerDay=1000
  182. accountMaxPostsPerDay=1000
  183. allowDeletion=True
  184. privateKeyPem,publicKeyPem,person,wfEndpoint= \
  185. createPerson(path,nickname,domain,port,httpPrefix,True,password)
  186. deleteAllPosts(path,nickname,domain,'inbox')
  187. deleteAllPosts(path,nickname,domain,'outbox')
  188. assert setSkillLevel(path,nickname,domain,'hacking',90)
  189. assert setRole(path,nickname,domain,'someproject','guru')
  190. if hasFollows:
  191. followPerson(path,nickname,domain,'bob','127.0.0.100:61936', \
  192. federationList,False)
  193. followerOfPerson(path,nickname,domain,'bob','127.0.0.100:61936', \
  194. federationList,False)
  195. if hasPosts:
  196. createPublicPost(path,nickname, domain, port,httpPrefix, \
  197. "No wise fish would go anywhere without a porpoise", \
  198. False, True, clientToServer,None,None,useBlurhash)
  199. createPublicPost(path,nickname, domain, port,httpPrefix, \
  200. "Curiouser and curiouser!", False, True, \
  201. clientToServer,None,None,useBlurhash)
  202. createPublicPost(path,nickname, domain, port,httpPrefix, \
  203. "In the gardens of memory, in the palace of dreams, that is where you and I shall meet", \
  204. False, True, clientToServer,None,None,useBlurhash)
  205. global testServerAliceRunning
  206. testServerAliceRunning = True
  207. maxMentions=10
  208. print('Server running: Alice')
  209. runDaemon(__version__,"instanceId",False,path,domain,port,port, \
  210. httpPrefix,federationList,maxMentions,False, \
  211. noreply,nolike,nopics,noannounce,cw,ocapAlways, \
  212. useTor,maxReplies, \
  213. domainMaxPostsPerDay,accountMaxPostsPerDay, \
  214. allowDeletion,True,True,False)
  215. def createServerBob(path: str,domain: str,port: int,federationList: [], \
  216. hasFollows: bool,hasPosts :bool,ocapAlways :bool):
  217. print('Creating test server: Bob on port '+str(port))
  218. if os.path.isdir(path):
  219. shutil.rmtree(path)
  220. os.mkdir(path)
  221. os.chdir(path)
  222. nickname='bob'
  223. httpPrefix='http'
  224. useTor=False
  225. clientToServer=False
  226. password='bobpass'
  227. noreply=False
  228. nolike=False
  229. nopics=False
  230. noannounce=False
  231. cw=False
  232. useBlurhash=False
  233. maxReplies=64
  234. domainMaxPostsPerDay=1000
  235. accountMaxPostsPerDay=1000
  236. allowDeletion=True
  237. privateKeyPem,publicKeyPem,person,wfEndpoint= \
  238. createPerson(path,nickname,domain,port,httpPrefix,True,password)
  239. deleteAllPosts(path,nickname,domain,'inbox')
  240. deleteAllPosts(path,nickname,domain,'outbox')
  241. assert setRole(path,nickname,domain,'bandname','bass player')
  242. assert setRole(path,nickname,domain,'bandname','publicist')
  243. if hasFollows:
  244. followPerson(path,nickname,domain, \
  245. 'alice','127.0.0.50:61935',federationList,False)
  246. followerOfPerson(path,nickname,domain, \
  247. 'alice','127.0.0.50:61935',federationList,False)
  248. if hasPosts:
  249. createPublicPost(path,nickname, domain, port,httpPrefix, \
  250. "It's your life, live it your way.", \
  251. False, True, clientToServer,None,None,useBlurhash)
  252. createPublicPost(path,nickname, domain, port,httpPrefix, \
  253. "One of the things I've realised is that I am very simple", \
  254. False, True, clientToServer,None,None,useBlurhash)
  255. createPublicPost(path,nickname, domain, port,httpPrefix, \
  256. "Quantum physics is a bit of a passion of mine", \
  257. False, True, clientToServer,None,None,useBlurhash)
  258. global testServerBobRunning
  259. testServerBobRunning = True
  260. maxMentions=10
  261. print('Server running: Bob')
  262. runDaemon(__version__,"instanceId",False,path,domain,port,port, \
  263. httpPrefix,federationList,maxMentions,False, \
  264. noreply,nolike,nopics,noannounce,cw,ocapAlways, \
  265. useTor,maxReplies, \
  266. domainMaxPostsPerDay,accountMaxPostsPerDay, \
  267. allowDeletion,True,True,False)
  268. def createServerEve(path: str,domain: str,port: int,federationList: [], \
  269. hasFollows: bool,hasPosts :bool,ocapAlways :bool):
  270. print('Creating test server: Eve on port '+str(port))
  271. if os.path.isdir(path):
  272. shutil.rmtree(path)
  273. os.mkdir(path)
  274. os.chdir(path)
  275. nickname='eve'
  276. httpPrefix='http'
  277. useTor=False
  278. clientToServer=False
  279. password='evepass'
  280. noreply=False
  281. nolike=False
  282. nopics=False
  283. noannounce=False
  284. cw=False
  285. maxReplies=64
  286. allowDeletion=True
  287. privateKeyPem,publicKeyPem,person,wfEndpoint= \
  288. createPerson(path,nickname,domain,port,httpPrefix,True,password)
  289. deleteAllPosts(path,nickname,domain,'inbox')
  290. deleteAllPosts(path,nickname,domain,'outbox')
  291. global testServerEveRunning
  292. testServerEveRunning = True
  293. maxMentions=10
  294. print('Server running: Eve')
  295. runDaemon(__version__,"instanceId",False,path,domain,port,port, \
  296. httpPrefix,federationList,maxMentions,False, \
  297. noreply,nolike,nopics,noannounce,cw,ocapAlways, \
  298. useTor,maxReplies,allowDeletion,True,True,False)
  299. def testPostMessageBetweenServers():
  300. print('Testing sending message from one server to the inbox of another')
  301. global testServerAliceRunning
  302. global testServerBobRunning
  303. testServerAliceRunning = False
  304. testServerBobRunning = False
  305. httpPrefix='http'
  306. useTor=False
  307. baseDir=os.getcwd()
  308. if os.path.isdir(baseDir+'/.tests'):
  309. shutil.rmtree(baseDir+'/.tests')
  310. os.mkdir(baseDir+'/.tests')
  311. ocapAlways=False
  312. # create the servers
  313. aliceDir=baseDir+'/.tests/alice'
  314. aliceDomain='127.0.0.50'
  315. alicePort=61935
  316. bobDir=baseDir+'/.tests/bob'
  317. bobDomain='127.0.0.100'
  318. bobPort=61936
  319. federationList=[bobDomain,aliceDomain]
  320. thrAlice = \
  321. threadWithTrace(target=createServerAlice, \
  322. args=(aliceDir,aliceDomain,alicePort, \
  323. federationList,False,False, \
  324. ocapAlways),daemon=True)
  325. thrBob = \
  326. threadWithTrace(target=createServerBob, \
  327. args=(bobDir,bobDomain,bobPort, \
  328. federationList,False,False, \
  329. ocapAlways),daemon=True)
  330. thrAlice.start()
  331. thrBob.start()
  332. assert thrAlice.isAlive()==True
  333. assert thrBob.isAlive()==True
  334. # wait for both servers to be running
  335. while not (testServerAliceRunning and testServerBobRunning):
  336. time.sleep(1)
  337. time.sleep(1)
  338. print('\n\n*******************************************************')
  339. print('Alice sends to Bob')
  340. os.chdir(aliceDir)
  341. sessionAlice = createSession(aliceDomain,alicePort,useTor)
  342. inReplyTo=None
  343. inReplyToAtomUri=None
  344. subject=None
  345. aliceSendThreads = []
  346. alicePostLog = []
  347. followersOnly=False
  348. saveToFile=True
  349. clientToServer=False
  350. ccUrl=None
  351. alicePersonCache={}
  352. aliceCachedWebfingers={}
  353. attachedImageFilename=baseDir+'/img/logo.png'
  354. mediaType=getAttachmentMediaType(attachedImageFilename)
  355. attachedImageDescription='Logo'
  356. useBlurhash=True
  357. # nothing in Alice's outbox
  358. outboxPath=aliceDir+'/accounts/alice@'+aliceDomain+'/outbox'
  359. assert len([name for name in os.listdir(outboxPath) if os.path.isfile(os.path.join(outboxPath, name))])==0
  360. sendResult = \
  361. sendPost(__version__, \
  362. sessionAlice,aliceDir,'alice', aliceDomain, alicePort, \
  363. 'bob', bobDomain, bobPort, ccUrl, httpPrefix, \
  364. 'Why is a mouse when it spins? #sillyquestion', followersOnly, \
  365. saveToFile, clientToServer,attachedImageFilename,mediaType, \
  366. attachedImageDescription,useBlurhash, federationList, \
  367. aliceSendThreads, alicePostLog, aliceCachedWebfingers, \
  368. alicePersonCache,inReplyTo, inReplyToAtomUri, subject)
  369. print('sendResult: '+str(sendResult))
  370. queuePath=bobDir+'/accounts/bob@'+bobDomain+'/queue'
  371. inboxPath=bobDir+'/accounts/bob@'+bobDomain+'/inbox'
  372. mPath=getMediaPath()
  373. mediaPath=aliceDir+'/'+mPath
  374. for i in range(30):
  375. if os.path.isdir(inboxPath):
  376. if len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])>0:
  377. if len([name for name in os.listdir(outboxPath) if os.path.isfile(os.path.join(outboxPath, name))])==1:
  378. if len([name for name in os.listdir(mediaPath) if os.path.isfile(os.path.join(mediaPath, name))])>0:
  379. break
  380. time.sleep(1)
  381. # Image attachment created
  382. assert len([name for name in os.listdir(mediaPath) if os.path.isfile(os.path.join(mediaPath, name))])>0
  383. # inbox item created
  384. assert len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])==1
  385. # queue item removed
  386. assert len([name for name in os.listdir(queuePath) if os.path.isfile(os.path.join(queuePath, name))])==0
  387. assert validInbox(bobDir,'bob',bobDomain)
  388. assert validInboxFilenames(bobDir,'bob',bobDomain,aliceDomain,alicePort)
  389. print('\n\n*******************************************************')
  390. print("Bob likes Alice's post")
  391. followerOfPerson(bobDir,'bob',bobDomain,'alice', \
  392. aliceDomain+':'+str(alicePort),federationList,False)
  393. followPerson(aliceDir,'alice',aliceDomain,'bob', \
  394. bobDomain+':'+str(bobPort),federationList,False)
  395. sessionBob = createSession(bobDomain,bobPort,useTor)
  396. bobSendThreads = []
  397. bobPostLog = []
  398. bobPersonCache={}
  399. bobCachedWebfingers={}
  400. statusNumber=None
  401. outboxPostFilename=None
  402. outboxPath=aliceDir+'/accounts/alice@'+aliceDomain+'/outbox'
  403. for name in os.listdir(outboxPath):
  404. if '#statuses#' in name:
  405. statusNumber=int(name.split('#statuses#')[1].replace('.json',''))
  406. outboxPostFilename=outboxPath+'/'+name
  407. assert statusNumber>0
  408. assert outboxPostFilename
  409. assert likePost(sessionBob,bobDir,federationList, \
  410. 'bob',bobDomain,bobPort,httpPrefix, \
  411. 'alice',aliceDomain,alicePort,[], \
  412. statusNumber,False,bobSendThreads,bobPostLog, \
  413. bobPersonCache,bobCachedWebfingers, \
  414. True,__version__)
  415. for i in range(20):
  416. if 'likes' in open(outboxPostFilename).read():
  417. break
  418. time.sleep(1)
  419. with open(outboxPostFilename, 'r') as fp:
  420. alicePostJson=commentjson.load(fp)
  421. pprint(alicePostJson)
  422. assert 'likes' in open(outboxPostFilename).read()
  423. print('\n\n*******************************************************')
  424. print("Bob repeats Alice's post")
  425. objectUrl=httpPrefix+'://'+aliceDomain+':'+str(alicePort)+'/users/alice/statuses/'+str(statusNumber)
  426. inboxPath=aliceDir+'/accounts/alice@'+aliceDomain+'/inbox'
  427. outboxPath=bobDir+'/accounts/bob@'+bobDomain+'/outbox'
  428. outboxBeforeAnnounceCount=len([name for name in os.listdir(outboxPath) if os.path.isfile(os.path.join(outboxPath, name))])
  429. beforeAnnounceCount=len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])
  430. assert beforeAnnounceCount==0
  431. print('inbox items before announce: '+str(beforeAnnounceCount))
  432. announcePublic(sessionBob,bobDir,federationList, \
  433. 'bob',bobDomain,bobPort,httpPrefix, \
  434. objectUrl, \
  435. False,bobSendThreads,bobPostLog, \
  436. bobPersonCache,bobCachedWebfingers, \
  437. True,__version__)
  438. announceMessageArrived=False
  439. for i in range(10):
  440. time.sleep(1)
  441. if os.path.isdir(inboxPath):
  442. if len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])>0:
  443. announceMessageArrived=True
  444. print('Announce message sent to Alice!')
  445. break
  446. afterAnnounceCount=len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])
  447. outboxAfterAnnounceCount=len([name for name in os.listdir(outboxPath) if os.path.isfile(os.path.join(outboxPath, name))])
  448. print('inbox items after announce: '+str(afterAnnounceCount))
  449. assert afterAnnounceCount==beforeAnnounceCount+1
  450. assert outboxAfterAnnounceCount==outboxBeforeAnnounceCount+1
  451. # stop the servers
  452. thrAlice.kill()
  453. thrAlice.join()
  454. assert thrAlice.isAlive()==False
  455. thrBob.kill()
  456. thrBob.join()
  457. assert thrBob.isAlive()==False
  458. os.chdir(baseDir)
  459. shutil.rmtree(aliceDir)
  460. shutil.rmtree(bobDir)
  461. def testFollowBetweenServersWithCapabilities():
  462. print('Testing sending a follow request from one server to another')
  463. global testServerAliceRunning
  464. global testServerBobRunning
  465. global testServerEveRunning
  466. testServerAliceRunning = False
  467. testServerBobRunning = False
  468. testServerEveRunning = False
  469. httpPrefix='http'
  470. useTor=False
  471. federationList=[]
  472. baseDir=os.getcwd()
  473. if os.path.isdir(baseDir+'/.tests'):
  474. shutil.rmtree(baseDir+'/.tests')
  475. os.mkdir(baseDir+'/.tests')
  476. ocapAlways=True
  477. # create the servers
  478. aliceDir=baseDir+'/.tests/alice'
  479. aliceDomain='127.0.0.42'
  480. alicePort=61935
  481. thrAlice = \
  482. threadWithTrace(target=createServerAlice, \
  483. args=(aliceDir,aliceDomain,alicePort, \
  484. federationList,False,False, \
  485. ocapAlways),daemon=True)
  486. bobDir=baseDir+'/.tests/bob'
  487. bobDomain='127.0.0.64'
  488. bobPort=61936
  489. thrBob = \
  490. threadWithTrace(target=createServerBob, \
  491. args=(bobDir,bobDomain,bobPort, \
  492. federationList,False,False, \
  493. ocapAlways),daemon=True)
  494. eveDir=baseDir+'/.tests/eve'
  495. eveDomain='127.0.0.55'
  496. evePort=61937
  497. thrEve = \
  498. threadWithTrace(target=createServerEve, \
  499. args=(eveDir,eveDomain,evePort, \
  500. federationList,False,False, \
  501. False),daemon=True)
  502. thrAlice.start()
  503. thrBob.start()
  504. thrEve.start()
  505. assert thrAlice.isAlive()==True
  506. assert thrBob.isAlive()==True
  507. assert thrEve.isAlive()==True
  508. # wait for all servers to be running
  509. ctr=0
  510. while not (testServerAliceRunning and testServerBobRunning and testServerEveRunning):
  511. time.sleep(1)
  512. ctr+=1
  513. if ctr>60:
  514. break
  515. print('Alice online: '+str(testServerAliceRunning))
  516. print('Bob online: '+str(testServerBobRunning))
  517. print('Eve online: '+str(testServerEveRunning))
  518. assert ctr<=60
  519. time.sleep(1)
  520. # In the beginning all was calm and there were no follows
  521. print('*********************************************************')
  522. print('Alice sends a follow request to Bob')
  523. print('Both are strictly enforcing object capabilities')
  524. os.chdir(aliceDir)
  525. sessionAlice = createSession(aliceDomain,alicePort,useTor)
  526. inReplyTo=None
  527. inReplyToAtomUri=None
  528. subject=None
  529. aliceSendThreads = []
  530. alicePostLog = []
  531. followersOnly=False
  532. saveToFile=True
  533. clientToServer=False
  534. ccUrl=None
  535. alicePersonCache={}
  536. aliceCachedWebfingers={}
  537. aliceSendThreads=[]
  538. alicePostLog=[]
  539. sendResult = \
  540. sendFollowRequest(sessionAlice,aliceDir, \
  541. 'alice',aliceDomain,alicePort,httpPrefix, \
  542. 'bob',bobDomain,bobPort,httpPrefix, \
  543. clientToServer,federationList, \
  544. aliceSendThreads,alicePostLog, \
  545. aliceCachedWebfingers,alicePersonCache, \
  546. True,__version__)
  547. print('sendResult: '+str(sendResult))
  548. bobCapsFilename=bobDir+'/accounts/bob@'+bobDomain+'/ocap/accept/'+httpPrefix+':##'+aliceDomain+':'+str(alicePort)+'#users#alice.json'
  549. aliceCapsFilename=aliceDir+'/accounts/alice@'+aliceDomain+'/ocap/granted/'+httpPrefix+':##'+bobDomain+':'+str(bobPort)+'#users#bob.json'
  550. for t in range(10):
  551. if os.path.isfile(bobDir+'/accounts/bob@'+bobDomain+'/followers.txt'):
  552. if os.path.isfile(aliceDir+'/accounts/alice@'+aliceDomain+'/following.txt'):
  553. if os.path.isfile(bobCapsFilename):
  554. if os.path.isfile(aliceCapsFilename):
  555. break
  556. time.sleep(1)
  557. with open(bobCapsFilename, 'r') as fp:
  558. bobCapsJson=commentjson.load(fp)
  559. if not bobCapsJson.get('capability'):
  560. print("Unexpected format for Bob's capabilities")
  561. pprint(bobCapsJson)
  562. assert False
  563. assert validInbox(bobDir,'bob',bobDomain)
  564. assert validInboxFilenames(bobDir,'bob',bobDomain,aliceDomain,alicePort)
  565. print('\n\n*********************************************************')
  566. print('Eve tries to send to Bob')
  567. sessionEve = createSession(eveDomain,evePort,useTor)
  568. eveSendThreads = []
  569. evePostLog = []
  570. evePersonCache={}
  571. eveCachedWebfingers={}
  572. eveSendThreads=[]
  573. evePostLog=[]
  574. useBlurhash=False
  575. sendResult = \
  576. sendPost(__version__, \
  577. sessionEve,eveDir,'eve', eveDomain, evePort, \
  578. 'bob', bobDomain, bobPort, ccUrl, \
  579. httpPrefix, 'Eve message', followersOnly, \
  580. saveToFile, clientToServer,None,None,None, \
  581. useBlurhash, federationList, eveSendThreads, \
  582. evePostLog, eveCachedWebfingers, \
  583. evePersonCache,inReplyTo, inReplyToAtomUri, subject)
  584. print('sendResult: '+str(sendResult))
  585. queuePath=bobDir+'/accounts/bob@'+bobDomain+'/queue'
  586. inboxPath=bobDir+'/accounts/bob@'+bobDomain+'/inbox'
  587. eveMessageArrived=False
  588. for i in range(10):
  589. time.sleep(1)
  590. if os.path.isdir(inboxPath):
  591. if len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])>1:
  592. eveMessageArrived=True
  593. print('Eve message sent to Bob!')
  594. break
  595. # capabilities should have prevented delivery
  596. assert eveMessageArrived==False
  597. print('Message from Eve to Bob was correctly rejected by object capabilities')
  598. print('\n\n*********************************************************')
  599. print('Alice sends a message to Bob')
  600. aliceSendThreads = []
  601. alicePostLog = []
  602. alicePersonCache={}
  603. aliceCachedWebfingers={}
  604. aliceSendThreads=[]
  605. alicePostLog=[]
  606. useBlurhash=False
  607. sendResult = \
  608. sendPost(__version__, \
  609. sessionAlice,aliceDir,'alice', aliceDomain, alicePort, \
  610. 'bob', bobDomain, bobPort, ccUrl, \
  611. httpPrefix, 'Alice message', followersOnly, saveToFile, \
  612. clientToServer,None,None,None,useBlurhash, federationList, \
  613. aliceSendThreads, alicePostLog, aliceCachedWebfingers, \
  614. alicePersonCache,inReplyTo, inReplyToAtomUri, subject)
  615. print('sendResult: '+str(sendResult))
  616. queuePath=bobDir+'/accounts/bob@'+bobDomain+'/queue'
  617. inboxPath=bobDir+'/accounts/bob@'+bobDomain+'/inbox'
  618. aliceMessageArrived=False
  619. for i in range(20):
  620. time.sleep(1)
  621. if os.path.isdir(inboxPath):
  622. if len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])>0:
  623. aliceMessageArrived=True
  624. print('Alice message sent to Bob!')
  625. break
  626. assert aliceMessageArrived==True
  627. print('Message from Alice to Bob succeeded, since it was granted capabilities')
  628. print('\n\n*********************************************************')
  629. print("\nBob changes Alice's capabilities so that she can't reply on his posts")
  630. bobCapsFilename= \
  631. bobDir+'/accounts/bob@'+bobDomain+'/ocap/accept/'+ \
  632. httpPrefix+':##'+aliceDomain+':'+str(alicePort)+'#users#alice.json'
  633. aliceCapsFilename= \
  634. aliceDir+'/accounts/alice@'+aliceDomain+'/ocap/granted/'+ \
  635. httpPrefix+':##'+bobDomain+':'+str(bobPort)+'#users#bob.json'
  636. sessionBob = createSession(bobDomain,bobPort,useTor)
  637. bobSendThreads = []
  638. bobPostLog = []
  639. bobPersonCache={}
  640. bobCachedWebfingers={}
  641. print("Bob's capabilities for Alice:")
  642. with open(bobCapsFilename, 'r') as fp:
  643. bobCapsJson=commentjson.load(fp)
  644. pprint(bobCapsJson)
  645. assert "inbox:noreply" not in bobCapsJson['capability']
  646. print("Alice's capabilities granted by Bob")
  647. with open(aliceCapsFilename, 'r') as fp:
  648. aliceCapsJson=commentjson.load(fp)
  649. pprint(aliceCapsJson)
  650. assert "inbox:noreply" not in aliceCapsJson['capability']
  651. newCapabilities=["inbox:write","objects:read","inbox:noreply"]
  652. sendCapabilitiesUpdate(sessionBob,bobDir,httpPrefix, \
  653. 'bob',bobDomain,bobPort, \
  654. httpPrefix+'://'+aliceDomain+':'+\
  655. str(alicePort)+'/users/alice',
  656. newCapabilities, \
  657. bobSendThreads, bobPostLog, \
  658. bobCachedWebfingers,bobPersonCache, \
  659. federationList,True,__version__)
  660. bobChanged=False
  661. bobNewCapsJson=None
  662. for i in range(20):
  663. time.sleep(1)
  664. with open(bobCapsFilename, 'r') as fp:
  665. bobNewCapsJson=commentjson.load(fp)
  666. if "inbox:noreply" in bobNewCapsJson['capability']:
  667. print("Bob's capabilities were changed")
  668. pprint(bobNewCapsJson)
  669. bobChanged=True
  670. break
  671. assert bobChanged
  672. aliceChanged=False
  673. aliceNewCapsJson=None
  674. for i in range(20):
  675. time.sleep(1)
  676. with open(aliceCapsFilename, 'r') as fp:
  677. aliceNewCapsJson=commentjson.load(fp)
  678. if "inbox:noreply" in aliceNewCapsJson['capability']:
  679. print("Alice's granted capabilities were changed")
  680. pprint(aliceNewCapsJson)
  681. aliceChanged=True
  682. break
  683. assert aliceChanged
  684. # check that the capabilities id has changed
  685. assert bobNewCapsJson['id']!=bobCapsJson['id']
  686. assert aliceNewCapsJson['id']!=aliceCapsJson['id']
  687. # stop the servers
  688. thrAlice.kill()
  689. thrAlice.join()
  690. assert thrAlice.isAlive()==False
  691. thrBob.kill()
  692. thrBob.join()
  693. assert thrBob.isAlive()==False
  694. thrEve.kill()
  695. thrEve.join()
  696. assert thrEve.isAlive()==False
  697. assert os.path.isfile(bobDir+'/accounts/bob@'+bobDomain+ \
  698. '/ocap/accept/'+httpPrefix+':##'+ \
  699. aliceDomain+':'+str(alicePort)+ \
  700. '#users#alice.json')
  701. assert os.path.isfile(aliceDir+'/accounts/alice@'+ \
  702. aliceDomain+'/ocap/granted/'+ \
  703. httpPrefix+':##'+bobDomain+':'+ \
  704. str(bobPort)+'#users#bob.json')
  705. assert 'alice@'+aliceDomain in open(bobDir+'/accounts/bob@'+bobDomain+'/followers.txt').read()
  706. assert 'bob@'+bobDomain in open(aliceDir+'/accounts/alice@'+aliceDomain+'/following.txt').read()
  707. # queue item removed
  708. assert len([name for name in os.listdir(queuePath) if os.path.isfile(os.path.join(queuePath, name))])==0
  709. os.chdir(baseDir)
  710. shutil.rmtree(baseDir+'/.tests')
  711. def testFollowBetweenServers():
  712. print('Testing sending a follow request from one server to another')
  713. global testServerAliceRunning
  714. global testServerBobRunning
  715. testServerAliceRunning = False
  716. testServerBobRunning = False
  717. httpPrefix='http'
  718. useTor=False
  719. federationList=[]
  720. baseDir=os.getcwd()
  721. if os.path.isdir(baseDir+'/.tests'):
  722. shutil.rmtree(baseDir+'/.tests')
  723. os.mkdir(baseDir+'/.tests')
  724. ocapAlways=False
  725. # create the servers
  726. aliceDir=baseDir+'/.tests/alice'
  727. aliceDomain='127.0.0.42'
  728. alicePort=61935
  729. thrAlice = \
  730. threadWithTrace(target=createServerAlice, \
  731. args=(aliceDir,aliceDomain,alicePort, \
  732. federationList,False,False, \
  733. ocapAlways),daemon=True)
  734. bobDir=baseDir+'/.tests/bob'
  735. bobDomain='127.0.0.64'
  736. bobPort=61936
  737. thrBob = \
  738. threadWithTrace(target=createServerBob, \
  739. args=(bobDir,bobDomain,bobPort, \
  740. federationList,False,False, \
  741. ocapAlways),daemon=True)
  742. thrAlice.start()
  743. thrBob.start()
  744. assert thrAlice.isAlive()==True
  745. assert thrBob.isAlive()==True
  746. # wait for all servers to be running
  747. ctr=0
  748. while not (testServerAliceRunning and testServerBobRunning):
  749. time.sleep(1)
  750. ctr+=1
  751. if ctr>60:
  752. break
  753. print('Alice online: '+str(testServerAliceRunning))
  754. print('Bob online: '+str(testServerBobRunning))
  755. assert ctr<=60
  756. time.sleep(1)
  757. # In the beginning all was calm and there were no follows
  758. print('*********************************************************')
  759. print('Alice sends a follow request to Bob')
  760. os.chdir(aliceDir)
  761. sessionAlice = createSession(aliceDomain,alicePort,useTor)
  762. inReplyTo=None
  763. inReplyToAtomUri=None
  764. subject=None
  765. aliceSendThreads = []
  766. alicePostLog = []
  767. followersOnly=False
  768. saveToFile=True
  769. clientToServer=False
  770. ccUrl=None
  771. alicePersonCache={}
  772. aliceCachedWebfingers={}
  773. aliceSendThreads=[]
  774. alicePostLog=[]
  775. sendResult = \
  776. sendFollowRequest(sessionAlice,aliceDir, \
  777. 'alice',aliceDomain,alicePort,httpPrefix, \
  778. 'bob',bobDomain,bobPort,httpPrefix, \
  779. clientToServer,federationList, \
  780. aliceSendThreads,alicePostLog, \
  781. aliceCachedWebfingers,alicePersonCache, \
  782. True,__version__)
  783. print('sendResult: '+str(sendResult))
  784. for t in range(10):
  785. if os.path.isfile(bobDir+'/accounts/bob@'+bobDomain+'/followers.txt'):
  786. if os.path.isfile(aliceDir+'/accounts/alice@'+aliceDomain+'/following.txt'):
  787. break
  788. time.sleep(1)
  789. assert validInbox(bobDir,'bob',bobDomain)
  790. assert validInboxFilenames(bobDir,'bob',bobDomain,aliceDomain,alicePort)
  791. print('\n\n*********************************************************')
  792. print('Alice sends a message to Bob')
  793. aliceSendThreads = []
  794. alicePostLog = []
  795. alicePersonCache={}
  796. aliceCachedWebfingers={}
  797. aliceSendThreads=[]
  798. alicePostLog=[]
  799. useBlurhash=False
  800. sendResult = \
  801. sendPost(__version__, \
  802. sessionAlice,aliceDir,'alice', aliceDomain, alicePort, \
  803. 'bob', bobDomain, bobPort, ccUrl, \
  804. httpPrefix, 'Alice message', followersOnly, saveToFile, \
  805. clientToServer,None,None,None,useBlurhash, federationList, \
  806. aliceSendThreads, alicePostLog, aliceCachedWebfingers, \
  807. alicePersonCache,inReplyTo, inReplyToAtomUri, subject)
  808. print('sendResult: '+str(sendResult))
  809. queuePath=bobDir+'/accounts/bob@'+bobDomain+'/queue'
  810. inboxPath=bobDir+'/accounts/bob@'+bobDomain+'/inbox'
  811. aliceMessageArrived=False
  812. for i in range(20):
  813. time.sleep(1)
  814. if os.path.isdir(inboxPath):
  815. if len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])>0:
  816. aliceMessageArrived=True
  817. print('Alice message sent to Bob!')
  818. break
  819. assert aliceMessageArrived==True
  820. print('Message from Alice to Bob succeeded')
  821. # stop the servers
  822. thrAlice.kill()
  823. thrAlice.join()
  824. assert thrAlice.isAlive()==False
  825. thrBob.kill()
  826. thrBob.join()
  827. assert thrBob.isAlive()==False
  828. assert 'alice@'+aliceDomain in open(bobDir+'/accounts/bob@'+bobDomain+'/followers.txt').read()
  829. assert 'bob@'+bobDomain in open(aliceDir+'/accounts/alice@'+aliceDomain+'/following.txt').read()
  830. # queue item removed
  831. assert len([name for name in os.listdir(queuePath) if os.path.isfile(os.path.join(queuePath, name))])==0
  832. os.chdir(baseDir)
  833. shutil.rmtree(baseDir+'/.tests')
  834. def testFollowersOfPerson():
  835. print('testFollowersOfPerson')
  836. currDir=os.getcwd()
  837. nickname='mxpop'
  838. domain='diva.domain'
  839. password='birb'
  840. port=80
  841. httpPrefix='https'
  842. federationList=[]
  843. baseDir=currDir+'/.tests_followersofperson'
  844. if os.path.isdir(baseDir):
  845. shutil.rmtree(baseDir)
  846. os.mkdir(baseDir)
  847. os.chdir(baseDir)
  848. createPerson(baseDir,nickname,domain,port,httpPrefix,True,password)
  849. createPerson(baseDir,'maxboardroom',domain,port,httpPrefix,True,password)
  850. createPerson(baseDir,'ultrapancake',domain,port,httpPrefix,True,password)
  851. createPerson(baseDir,'drokk',domain,port,httpPrefix,True,password)
  852. createPerson(baseDir,'sausagedog',domain,port,httpPrefix,True,password)
  853. clearFollows(baseDir,nickname,domain)
  854. followPerson(baseDir,nickname,domain,'maxboardroom',domain,federationList,False)
  855. followPerson(baseDir,'drokk',domain,'ultrapancake',domain,federationList,False)
  856. # deliberate duplication
  857. followPerson(baseDir,'drokk',domain,'ultrapancake',domain,federationList,False)
  858. followPerson(baseDir,'sausagedog',domain,'ultrapancake',domain,federationList,False)
  859. followPerson(baseDir,nickname,domain,'ultrapancake',domain,federationList,False)
  860. followPerson(baseDir,nickname,domain,'someother','randodomain.net',federationList,False)
  861. followList=getFollowersOfPerson(baseDir,'ultrapancake',domain)
  862. assert len(followList)==3
  863. assert 'mxpop@'+domain in followList
  864. assert 'drokk@'+domain in followList
  865. assert 'sausagedog@'+domain in followList
  866. os.chdir(currDir)
  867. shutil.rmtree(baseDir)
  868. def testNoOfFollowersOnDomain():
  869. print('testNoOfFollowersOnDomain')
  870. currDir=os.getcwd()
  871. nickname='mxpop'
  872. domain='diva.domain'
  873. otherdomain='soup.dragon'
  874. password='birb'
  875. port=80
  876. httpPrefix='https'
  877. federationList=[]
  878. baseDir=currDir+'/.tests_nooffollowersOndomain'
  879. if os.path.isdir(baseDir):
  880. shutil.rmtree(baseDir)
  881. os.mkdir(baseDir)
  882. os.chdir(baseDir)
  883. createPerson(baseDir,nickname,domain,port,httpPrefix,True,password)
  884. createPerson(baseDir,'maxboardroom',otherdomain,port,httpPrefix,True,password)
  885. createPerson(baseDir,'ultrapancake',otherdomain,port,httpPrefix,True,password)
  886. createPerson(baseDir,'drokk',otherdomain,port,httpPrefix,True,password)
  887. createPerson(baseDir,'sausagedog',otherdomain,port,httpPrefix,True,password)
  888. followPerson(baseDir,'drokk',otherdomain,nickname,domain,federationList,False)
  889. followPerson(baseDir,'sausagedog',otherdomain,nickname,domain,federationList,False)
  890. followPerson(baseDir,'maxboardroom',otherdomain,nickname,domain,federationList,False)
  891. followerOfPerson(baseDir,nickname,domain,'cucumber','sandwiches.party',federationList,False)
  892. followerOfPerson(baseDir,nickname,domain,'captainsensible','damned.zone',federationList,False)
  893. followerOfPerson(baseDir,nickname,domain,'pilchard','zombies.attack',federationList,False)
  894. followerOfPerson(baseDir,nickname,domain,'drokk',otherdomain,federationList,False)
  895. followerOfPerson(baseDir,nickname,domain,'sausagedog',otherdomain,federationList,False)
  896. followerOfPerson(baseDir,nickname,domain,'maxboardroom',otherdomain,federationList,False)
  897. followersOnOtherDomain=noOfFollowersOnDomain(baseDir,nickname+'@'+domain, otherdomain)
  898. assert followersOnOtherDomain==3
  899. unfollowerOfPerson(baseDir,nickname,domain,'sausagedog',otherdomain)
  900. followersOnOtherDomain=noOfFollowersOnDomain(baseDir,nickname+'@'+domain, otherdomain)
  901. assert followersOnOtherDomain==2
  902. os.chdir(currDir)
  903. shutil.rmtree(baseDir)
  904. def testGroupFollowers():
  905. print('testGroupFollowers')
  906. currDir=os.getcwd()
  907. nickname='test735'
  908. domain='mydomain.com'
  909. password='somepass'
  910. port=80
  911. httpPrefix='https'
  912. federationList=[]
  913. baseDir=currDir+'/.tests_testgroupfollowers'
  914. if os.path.isdir(baseDir):
  915. shutil.rmtree(baseDir)
  916. os.mkdir(baseDir)
  917. os.chdir(baseDir)
  918. createPerson(baseDir,nickname,domain,port,httpPrefix,True,password)
  919. clearFollowers(baseDir,nickname,domain)
  920. followerOfPerson(baseDir,nickname,domain,'badger','wild.domain',federationList,False)
  921. followerOfPerson(baseDir,nickname,domain,'squirrel','wild.domain',federationList,False)
  922. followerOfPerson(baseDir,nickname,domain,'rodent','wild.domain',federationList,False)
  923. followerOfPerson(baseDir,nickname,domain,'utterly','clutterly.domain',federationList,False)
  924. followerOfPerson(baseDir,nickname,domain,'zonked','zzz.domain',federationList,False)
  925. followerOfPerson(baseDir,nickname,domain,'nap','zzz.domain',federationList,False)
  926. grouped=groupFollowersByDomain(baseDir,nickname,domain)
  927. assert len(grouped.items())==3
  928. assert grouped.get('zzz.domain')
  929. assert grouped.get('clutterly.domain')
  930. assert grouped.get('wild.domain')
  931. assert len(grouped['zzz.domain'])==2
  932. assert len(grouped['wild.domain'])==3
  933. assert len(grouped['clutterly.domain'])==1
  934. os.chdir(currDir)
  935. shutil.rmtree(baseDir)
  936. def testFollows():
  937. print('testFollows')
  938. currDir=os.getcwd()
  939. nickname='test529'
  940. domain='testdomain.com'
  941. password='mypass'
  942. port=80
  943. httpPrefix='https'
  944. federationList=['wild.com','mesh.com']
  945. baseDir=currDir+'/.tests_testfollows'
  946. if os.path.isdir(baseDir):
  947. shutil.rmtree(baseDir)
  948. os.mkdir(baseDir)
  949. os.chdir(baseDir)
  950. createPerson(baseDir,nickname,domain,port,httpPrefix,True,password)
  951. clearFollows(baseDir,nickname,domain)
  952. followPerson(baseDir,nickname,domain,'badger','wild.com',federationList,False)
  953. followPerson(baseDir,nickname,domain,'squirrel','secret.com',federationList,False)
  954. followPerson(baseDir,nickname,domain,'rodent','drainpipe.com',federationList,False)
  955. followPerson(baseDir,nickname,domain,'batman','mesh.com',federationList,False)
  956. followPerson(baseDir,nickname,domain,'giraffe','trees.com',federationList,False)
  957. f = open(baseDir+'/accounts/'+nickname+'@'+domain+'/following.txt', "r")
  958. domainFound=False
  959. for followingDomain in f:
  960. testDomain=followingDomain.split('@')[1].replace('\n','')
  961. if testDomain=='mesh.com':
  962. domainFound=True
  963. if testDomain not in federationList:
  964. print(testDomain)
  965. assert(False)
  966. assert(domainFound)
  967. unfollowPerson(baseDir,nickname,domain,'batman','mesh.com')
  968. domainFound=False
  969. for followingDomain in f:
  970. testDomain=followingDomain.split('@')[1].replace('\n','')
  971. if testDomain=='mesh.com':
  972. domainFound=True
  973. assert(domainFound==False)
  974. clearFollowers(baseDir,nickname,domain)
  975. followerOfPerson(baseDir,nickname,domain,'badger','wild.com',federationList,False)
  976. followerOfPerson(baseDir,nickname,domain,'squirrel','secret.com',federationList,False)
  977. followerOfPerson(baseDir,nickname,domain,'rodent','drainpipe.com',federationList,False)
  978. followerOfPerson(baseDir,nickname,domain,'batman','mesh.com',federationList,False)
  979. followerOfPerson(baseDir,nickname,domain,'giraffe','trees.com',federationList,False)
  980. f = open(baseDir+'/accounts/'+nickname+'@'+domain+'/followers.txt', "r")
  981. for followerDomain in f:
  982. testDomain=followerDomain.split('@')[1].replace('\n','')
  983. if testDomain not in federationList:
  984. print(testDomain)
  985. assert(False)
  986. os.chdir(currDir)
  987. shutil.rmtree(baseDir)
  988. def testCreatePerson():
  989. print('testCreatePerson')
  990. currDir=os.getcwd()
  991. nickname='test382'
  992. domain='badgerdomain.com'
  993. password='mypass'
  994. port=80
  995. httpPrefix='https'
  996. clientToServer=False
  997. useBlurhash=False
  998. baseDir=currDir+'/.tests_createperson'
  999. if os.path.isdir(baseDir):
  1000. shutil.rmtree(baseDir)
  1001. os.mkdir(baseDir)
  1002. os.chdir(baseDir)
  1003. privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(baseDir,nickname,domain,port,httpPrefix,True,password)
  1004. assert os.path.isfile(baseDir+'/accounts/passwords')
  1005. deleteAllPosts(baseDir,nickname,domain,'inbox')
  1006. deleteAllPosts(baseDir,nickname,domain,'outbox')
  1007. setDisplayNickname(baseDir,nickname,domain,'badger')
  1008. setBio(baseDir,nickname,domain,'Randomly roaming in your backyard')
  1009. archivePostsForPerson(nickname,domain,baseDir,'inbox',None,4)
  1010. archivePostsForPerson(nickname,domain,baseDir,'outbox',None,4)
  1011. createPublicPost(baseDir,nickname, domain, port,httpPrefix, "G'day world!", False, True, clientToServer,None,None,useBlurhash, None, None, 'Not suitable for Vogons')
  1012. os.chdir(currDir)
  1013. shutil.rmtree(baseDir)
  1014. def testDelegateRoles():
  1015. print('testDelegateRoles')
  1016. currDir=os.getcwd()
  1017. nickname='test382'
  1018. nicknameDelegated='test383'
  1019. domain='badgerdomain.com'
  1020. password='mypass'
  1021. port=80
  1022. httpPrefix='https'
  1023. clientToServer=False
  1024. useBlurhash=False
  1025. baseDir=currDir+'/.tests_delegaterole'
  1026. if os.path.isdir(baseDir):
  1027. shutil.rmtree(baseDir)
  1028. os.mkdir(baseDir)
  1029. os.chdir(baseDir)
  1030. privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(baseDir,nickname,domain,port,httpPrefix,True,password)
  1031. privateKeyPem,publicKeyPem,person,wfEndpoint=createPerson(baseDir,nicknameDelegated,domain,port,httpPrefix,True,'insecure')
  1032. httpPrefix='http'
  1033. project='artechoke'
  1034. role='delegator'
  1035. newRoleJson = {
  1036. 'type': 'Delegate',
  1037. 'actor': httpPrefix+'://'+domain+'/users/'+nickname,
  1038. 'object': {
  1039. 'type': 'Role',
  1040. 'actor': httpPrefix+'://'+domain+'/users/'+nicknameDelegated,
  1041. 'object': project+';'+role,
  1042. 'to': [],
  1043. 'cc': []
  1044. },
  1045. 'to': [],
  1046. 'cc': []
  1047. }
  1048. assert outboxDelegate(baseDir,nickname,newRoleJson,False)
  1049. # second time delegation has already happened so should return false
  1050. assert outboxDelegate(baseDir,nickname,newRoleJson,False)==False
  1051. assert '"delegator"' in open(baseDir+'/accounts/'+nickname+'@'+domain+'.json').read()
  1052. assert '"delegator"' in open(baseDir+'/accounts/'+nicknameDelegated+'@'+domain+'.json').read()
  1053. newRoleJson = {
  1054. 'type': 'Delegate',
  1055. 'actor': httpPrefix+'://'+domain+'/users/'+nicknameDelegated,
  1056. 'object': {
  1057. 'type': 'Role',
  1058. 'actor': httpPrefix+'://'+domain+'/users/'+nickname,
  1059. 'object': 'otherproject;otherrole',
  1060. 'to': [],
  1061. 'cc': []
  1062. },
  1063. 'to': [],
  1064. 'cc': []
  1065. }
  1066. # non-delegators cannot assign roles
  1067. assert outboxDelegate(baseDir,nicknameDelegated,newRoleJson,False)==False
  1068. assert '"otherrole"' not in open(baseDir+'/accounts/'+nickname+'@'+domain+'.json').read()
  1069. os.chdir(currDir)
  1070. shutil.rmtree(baseDir)
  1071. def testAuthentication():
  1072. print('testAuthentication')
  1073. currDir=os.getcwd()
  1074. nickname='test8743'
  1075. password='SuperSecretPassword12345'
  1076. baseDir=currDir+'/.tests_authentication'
  1077. if os.path.isdir(baseDir):
  1078. shutil.rmtree(baseDir)
  1079. os.mkdir(baseDir)
  1080. os.chdir(baseDir)
  1081. assert storeBasicCredentials(baseDir,'othernick','otherpass')
  1082. assert storeBasicCredentials(baseDir,'bad:nick','otherpass')==False
  1083. assert storeBasicCredentials(baseDir,'badnick','otherpa:ss')==False
  1084. assert storeBasicCredentials(baseDir,nickname,password)
  1085. authHeader=createBasicAuthHeader(nickname,password)
  1086. assert authorizeBasic(baseDir,'/users/'+nickname+'/inbox',authHeader,False)
  1087. assert authorizeBasic(baseDir,'/users/'+nickname,authHeader,False)==False
  1088. assert authorizeBasic(baseDir,'/users/othernick/inbox',authHeader,False)==False
  1089. authHeader=createBasicAuthHeader(nickname,password+'1')
  1090. assert authorizeBasic(baseDir,'/users/'+nickname+'/inbox',authHeader,False)==False
  1091. password='someOtherPassword'
  1092. assert storeBasicCredentials(baseDir,nickname,password)
  1093. authHeader=createBasicAuthHeader(nickname,password)
  1094. assert authorizeBasic(baseDir,'/users/'+nickname+'/inbox',authHeader,False)
  1095. os.chdir(currDir)
  1096. shutil.rmtree(baseDir)
  1097. def testClientToServer():
  1098. print('Testing sending a post via c2s')
  1099. global testServerAliceRunning
  1100. global testServerBobRunning
  1101. testServerAliceRunning = False
  1102. testServerBobRunning = False
  1103. httpPrefix='http'
  1104. useTor=False
  1105. federationList=[]
  1106. baseDir=os.getcwd()
  1107. if os.path.isdir(baseDir+'/.tests'):
  1108. shutil.rmtree(baseDir+'/.tests')
  1109. os.mkdir(baseDir+'/.tests')
  1110. ocapAlways=False
  1111. # create the servers
  1112. aliceDir=baseDir+'/.tests/alice'
  1113. aliceDomain='127.0.0.42'
  1114. alicePort=61935
  1115. thrAlice = \
  1116. threadWithTrace(target=createServerAlice, \
  1117. args=(aliceDir,aliceDomain,alicePort, \
  1118. federationList,False,False, \
  1119. ocapAlways),daemon=True)
  1120. bobDir=baseDir+'/.tests/bob'
  1121. bobDomain='127.0.0.64'
  1122. bobPort=61936
  1123. thrBob = \
  1124. threadWithTrace(target=createServerBob, \
  1125. args=(bobDir,bobDomain,bobPort, \
  1126. federationList,False,False, \
  1127. ocapAlways),daemon=True)
  1128. thrAlice.start()
  1129. thrBob.start()
  1130. assert thrAlice.isAlive()==True
  1131. assert thrBob.isAlive()==True
  1132. # wait for both servers to be running
  1133. ctr=0
  1134. while not (testServerAliceRunning and testServerBobRunning):
  1135. time.sleep(1)
  1136. ctr+=1
  1137. if ctr>60:
  1138. break
  1139. print('Alice online: '+str(testServerAliceRunning))
  1140. print('Bob online: '+str(testServerBobRunning))
  1141. time.sleep(1)
  1142. print('\n\n*******************************************************')
  1143. print('Alice sends to Bob via c2s')
  1144. sessionAlice = createSession(aliceDomain,alicePort,useTor)
  1145. followersOnly=False
  1146. attachedImageFilename=baseDir+'/img/logo.png'
  1147. mediaType=getAttachmentMediaType(attachedImageFilename)
  1148. attachedImageDescription='Logo'
  1149. useBlurhash=False
  1150. cachedWebfingers={}
  1151. personCache={}
  1152. password='alicepass'
  1153. outboxPath=aliceDir+'/accounts/alice@'+aliceDomain+'/outbox'
  1154. inboxPath=bobDir+'/accounts/bob@'+bobDomain+'/inbox'
  1155. assert len([name for name in os.listdir(outboxPath) if os.path.isfile(os.path.join(outboxPath, name))])==0
  1156. assert len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])==0
  1157. sendResult= \
  1158. sendPostViaServer(__version__, \
  1159. aliceDir,sessionAlice,'alice',password, \
  1160. aliceDomain,alicePort, \
  1161. 'bob',bobDomain,bobPort,None, \
  1162. httpPrefix,'Sent from my ActivityPub client',followersOnly, \
  1163. attachedImageFilename,mediaType, \
  1164. attachedImageDescription,useBlurhash, \
  1165. cachedWebfingers,personCache, \
  1166. True,None,None,None)
  1167. print('sendResult: '+str(sendResult))
  1168. for i in range(30):
  1169. if os.path.isdir(outboxPath):
  1170. if len([name for name in os.listdir(outboxPath) if os.path.isfile(os.path.join(outboxPath, name))])==1:
  1171. break
  1172. time.sleep(1)
  1173. assert len([name for name in os.listdir(outboxPath) if os.path.isfile(os.path.join(outboxPath, name))])==1
  1174. print(">>> c2s post arrived in Alice's outbox")
  1175. for i in range(30):
  1176. if os.path.isdir(inboxPath):
  1177. if len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])==1:
  1178. break
  1179. time.sleep(1)
  1180. assert len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])==1
  1181. print(">>> s2s post arrived in Bob's inbox")
  1182. print("c2s send success")
  1183. print('\n\nGetting message id for the post')
  1184. statusNumber=0
  1185. outboxPostFilename=None
  1186. outboxPostId=None
  1187. for name in os.listdir(outboxPath):
  1188. if '#statuses#' in name:
  1189. statusNumber=int(name.split('#statuses#')[1].replace('.json','').replace('#activity',''))
  1190. outboxPostFilename=outboxPath+'/'+name
  1191. with open(outboxPostFilename, 'r') as fp:
  1192. postJsonObject=commentjson.load(fp)
  1193. outboxPostId=postJsonObject['id'].replace('/activity','')
  1194. assert outboxPostId
  1195. print('message id obtained: '+outboxPostId)
  1196. assert validInbox(bobDir,'bob',bobDomain)
  1197. assert validInboxFilenames(bobDir,'bob',bobDomain,aliceDomain,alicePort)
  1198. print('\n\nAlice follows Bob')
  1199. sendFollowRequestViaServer(aliceDir,sessionAlice, \
  1200. 'alice',password, \
  1201. aliceDomain,alicePort, \
  1202. 'bob',bobDomain,bobPort, \
  1203. httpPrefix, \
  1204. cachedWebfingers,personCache, \
  1205. True,__version__)
  1206. for t in range(10):
  1207. if os.path.isfile(bobDir+'/accounts/bob@'+bobDomain+'/followers.txt'):
  1208. if 'alice@'+aliceDomain+':'+str(alicePort) in open(bobDir+'/accounts/bob@'+bobDomain+'/followers.txt').read():
  1209. if os.path.isfile(aliceDir+'/accounts/alice@'+aliceDomain+'/following.txt'):
  1210. if 'bob@'+bobDomain+':'+str(bobPort) in open(aliceDir+'/accounts/alice@'+aliceDomain+'/following.txt').read():
  1211. break
  1212. time.sleep(1)
  1213. assert os.path.isfile(bobDir+'/accounts/bob@'+bobDomain+'/followers.txt')
  1214. assert os.path.isfile(aliceDir+'/accounts/alice@'+aliceDomain+'/following.txt')
  1215. assert 'alice@'+aliceDomain+':'+str(alicePort) in open(bobDir+'/accounts/bob@'+bobDomain+'/followers.txt').read()
  1216. assert 'bob@'+bobDomain+':'+str(bobPort) in open(aliceDir+'/accounts/alice@'+aliceDomain+'/following.txt').read()
  1217. assert validInbox(bobDir,'bob',bobDomain)
  1218. assert validInboxFilenames(bobDir,'bob',bobDomain,aliceDomain,alicePort)
  1219. print('\n\nBob follows Alice')
  1220. sendFollowRequestViaServer(aliceDir,sessionAlice, \
  1221. 'bob','bobpass', \
  1222. bobDomain,bobPort, \
  1223. 'alice',aliceDomain,alicePort, \
  1224. httpPrefix, \
  1225. cachedWebfingers,personCache, \
  1226. True,__version__)
  1227. for t in range(10):
  1228. if os.path.isfile(aliceDir+'/accounts/alice@'+aliceDomain+'/followers.txt'):
  1229. if 'bob@'+bobDomain+':'+str(bobPort) in open(aliceDir+'/accounts/alice@'+aliceDomain+'/followers.txt').read():
  1230. if os.path.isfile(bobDir+'/accounts/bob@'+bobDomain+'/following.txt'):
  1231. if 'alice@'+aliceDomain+':'+str(alicePort) in open(bobDir+'/accounts/bob@'+bobDomain+'/following.txt').read():
  1232. break
  1233. time.sleep(1)
  1234. assert os.path.isfile(aliceDir+'/accounts/alice@'+aliceDomain+'/followers.txt')
  1235. assert os.path.isfile(bobDir+'/accounts/bob@'+bobDomain+'/following.txt')
  1236. assert 'bob@'+bobDomain+':'+str(bobPort) in open(aliceDir+'/accounts/alice@'+aliceDomain+'/followers.txt').read()
  1237. assert 'alice@'+aliceDomain+':'+str(alicePort) in open(bobDir+'/accounts/bob@'+bobDomain+'/following.txt').read()
  1238. print('\n\nBob likes the post')
  1239. sessionBob = createSession(bobDomain,bobPort,useTor)
  1240. password='bobpass'
  1241. outboxPath=bobDir+'/accounts/bob@'+bobDomain+'/outbox'
  1242. inboxPath=aliceDir+'/accounts/alice@'+aliceDomain+'/inbox'
  1243. print(str(len([name for name in os.listdir(outboxPath) if os.path.isfile(os.path.join(outboxPath, name))])))
  1244. assert len([name for name in os.listdir(outboxPath) if os.path.isfile(os.path.join(outboxPath, name))])==1
  1245. print(str(len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])))
  1246. assert len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])==1
  1247. sendLikeViaServer(bobDir,sessionBob, \
  1248. 'bob','bobpass', \
  1249. bobDomain,bobPort, \
  1250. httpPrefix,outboxPostId, \
  1251. cachedWebfingers,personCache, \
  1252. True,__version__)
  1253. for i in range(20):
  1254. if os.path.isdir(outboxPath) and os.path.isdir(inboxPath):
  1255. if len([name for name in os.listdir(outboxPath) if os.path.isfile(os.path.join(outboxPath, name))])==2:
  1256. if len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])==1:
  1257. break
  1258. time.sleep(1)
  1259. assert len([name for name in os.listdir(outboxPath) if os.path.isfile(os.path.join(outboxPath, name))])==2
  1260. assert len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])==1
  1261. print('Post liked')
  1262. print('\n\nBob repeats the post')
  1263. print(str(len([name for name in os.listdir(outboxPath) if os.path.isfile(os.path.join(outboxPath, name))])))
  1264. assert len([name for name in os.listdir(outboxPath) if os.path.isfile(os.path.join(outboxPath, name))])==2
  1265. print(str(len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])))
  1266. assert len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])==1
  1267. sendAnnounceViaServer(bobDir,sessionBob,'bob',password, \
  1268. bobDomain,bobPort, \
  1269. httpPrefix,outboxPostId, \
  1270. cachedWebfingers, \
  1271. personCache,True,__version__)
  1272. for i in range(20):
  1273. if os.path.isdir(outboxPath) and os.path.isdir(inboxPath):
  1274. if len([name for name in os.listdir(outboxPath) if os.path.isfile(os.path.join(outboxPath, name))])==3:
  1275. if len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])==2:
  1276. break
  1277. time.sleep(1)
  1278. assert len([name for name in os.listdir(outboxPath) if os.path.isfile(os.path.join(outboxPath, name))])==3
  1279. assert len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])==2
  1280. print('Post repeated')
  1281. inboxPath=bobDir+'/accounts/bob@'+bobDomain+'/inbox'
  1282. outboxPath=aliceDir+'/accounts/alice@'+aliceDomain+'/outbox'
  1283. postsBefore = len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])
  1284. print('\n\nAlice deletes her post: '+outboxPostId+' '+str(postsBefore))
  1285. password='alicepass'
  1286. sendDeleteViaServer(aliceDir,sessionAlice,'alice',password,
  1287. aliceDomain,alicePort, \
  1288. httpPrefix,outboxPostId, \
  1289. cachedWebfingers,personCache, \
  1290. True,__version__)
  1291. for i in range(30):
  1292. if os.path.isdir(inboxPath):
  1293. if len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])==postsBefore-1:
  1294. break
  1295. time.sleep(1)
  1296. assert len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])==postsBefore-1
  1297. print(">>> post deleted from Alice's outbox and Bob's inbox")
  1298. assert validInbox(bobDir,'bob',bobDomain)
  1299. assert validInboxFilenames(bobDir,'bob',bobDomain,aliceDomain,alicePort)
  1300. print('\n\nAlice unfollows Bob')
  1301. password='alicepass'
  1302. sendUnfollowRequestViaServer(baseDir,sessionAlice, \
  1303. 'alice',password, \
  1304. aliceDomain,alicePort, \
  1305. 'bob',bobDomain,bobPort, \
  1306. httpPrefix, \
  1307. cachedWebfingers,personCache, \
  1308. True,__version__)
  1309. for t in range(10):
  1310. if 'alice@'+aliceDomain+':'+str(alicePort) not in open(bobDir+'/accounts/bob@'+bobDomain+'/followers.txt').read():
  1311. if 'bob@'+bobDomain+':'+str(bobPort) not in open(aliceDir+'/accounts/alice@'+aliceDomain+'/following.txt').read():
  1312. break
  1313. time.sleep(1)
  1314. assert os.path.isfile(bobDir+'/accounts/bob@'+bobDomain+'/followers.txt')
  1315. assert os.path.isfile(aliceDir+'/accounts/alice@'+aliceDomain+'/following.txt')
  1316. assert 'alice@'+aliceDomain+':'+str(alicePort) not in open(bobDir+'/accounts/bob@'+bobDomain+'/followers.txt').read()
  1317. assert 'bob@'+bobDomain+':'+str(bobPort) not in open(aliceDir+'/accounts/alice@'+aliceDomain+'/following.txt').read()
  1318. assert validInbox(bobDir,'bob',bobDomain)
  1319. assert validInboxFilenames(bobDir,'bob',bobDomain,aliceDomain,alicePort)
  1320. assert validInbox(aliceDir,'alice',aliceDomain)
  1321. assert validInboxFilenames(aliceDir,'alice',aliceDomain,bobDomain,bobPort)
  1322. # stop the servers
  1323. thrAlice.kill()
  1324. thrAlice.join()
  1325. assert thrAlice.isAlive()==False
  1326. thrBob.kill()
  1327. thrBob.join()
  1328. assert thrBob.isAlive()==False
  1329. os.chdir(baseDir)
  1330. #shutil.rmtree(aliceDir)
  1331. #shutil.rmtree(bobDir)
  1332. def testActorParsing():
  1333. print('testActorParsing')
  1334. actor='https://mydomain:72/users/mynick'
  1335. domain,port=getDomainFromActor(actor)
  1336. assert domain=='mydomain'
  1337. assert port==72
  1338. nickname=getNicknameFromActor(actor)
  1339. assert nickname=='mynick'
  1340. actor='https://randomain/users/rando'
  1341. domain,port=getDomainFromActor(actor)
  1342. assert domain=='randomain'
  1343. nickname=getNicknameFromActor(actor)
  1344. assert nickname=='rando'
  1345. actor='https://otherdomain:49/@othernick'
  1346. domain,port=getDomainFromActor(actor)
  1347. assert domain=='otherdomain'
  1348. assert port==49
  1349. nickname=getNicknameFromActor(actor)
  1350. assert nickname=='othernick'
  1351. def testWebLinks():
  1352. print('testWebLinks')
  1353. exampleText='This post has a web links https://somesite.net\n\nAnd some other text'
  1354. linkedText=addWebLinks(exampleText)
  1355. assert '<a href="https://somesite.net" rel="nofollow noopener" target="_blank"><span class="invisible">https://</span><span class="ellipsis">somesite.net</span></a' in linkedText
  1356. exampleText='This post has a very long web link\n\nhttp://cbwebewuvfuftdiudbqd33dddbbyuef23fyug3bfhcyu2fct2cuyqbcbucuwvckiwyfgewfvqejbchevbhwevuevwbqebqekveqvuvjfkf.onion\n\nAnd some other text'
  1357. linkedText=addWebLinks(exampleText)
  1358. assert 'ellipsis' in linkedText
  1359. def testAddEmoji():
  1360. print('testAddEmoji')
  1361. content='Emoji :lemon: :strawberry: :banana:'
  1362. httpPrefix='http'
  1363. nickname='testuser'
  1364. domain='testdomain.net'
  1365. port=3682
  1366. recipients=[]
  1367. hashtags={}
  1368. baseDir=os.getcwd()
  1369. baseDirOriginal=os.getcwd()
  1370. path=baseDir+'/.tests'
  1371. if not os.path.isdir(path):
  1372. os.mkdir(path)
  1373. path=baseDir+'/.tests/emoji'
  1374. if os.path.isdir(path):
  1375. shutil.rmtree(path)
  1376. os.mkdir(path)
  1377. baseDir=path
  1378. path=baseDir+'/emoji'
  1379. if os.path.isdir(path):
  1380. shutil.rmtree(path)
  1381. os.mkdir(path)
  1382. copytree(baseDirOriginal+'/emoji',baseDir+'/emoji')
  1383. os.chdir(baseDir)
  1384. privateKeyPem,publicKeyPem,person,wfEndpoint= \
  1385. createPerson(baseDir,nickname,domain,port,httpPrefix,True,'password')
  1386. contentModified= \
  1387. addHtmlTags(baseDir,httpPrefix, \
  1388. nickname,domain,content, \
  1389. recipients,hashtags)
  1390. tags=[]
  1391. for tagName,tag in hashtags.items():
  1392. tags.append(tag)
  1393. content=contentModified
  1394. contentModified=replaceEmojiFromTags(content,tags,'content')
  1395. assert 'img src' in contentModified
  1396. os.chdir(baseDirOriginal)
  1397. shutil.rmtree(baseDirOriginal+'/.tests')
  1398. def testGetStatusNumber():
  1399. print('testGetStatusNumber')
  1400. prevStatusNumber=None
  1401. for i in range(1,20):
  1402. statusNumber,published = getStatusNumber()
  1403. if prevStatusNumber:
  1404. assert len(statusNumber) == 18
  1405. assert int(statusNumber) > prevStatusNumber
  1406. prevStatusNumber=int(statusNumber)
  1407. def runAllTests():
  1408. print('Running tests...')
  1409. testGetStatusNumber()
  1410. testAddEmoji()
  1411. testWebLinks()
  1412. testActorParsing()
  1413. testHttpsig()
  1414. testCache()
  1415. testThreads()
  1416. testCreatePerson()
  1417. testAuthentication()
  1418. testFollowersOfPerson()
  1419. testNoOfFollowersOnDomain()
  1420. testFollows()
  1421. testGroupFollowers()
  1422. testDelegateRoles()
  1423. print('Tests succeeded\n')