tests.py 67 KB

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