epicyon/tests.py

3506 lines
134 KiB
Python
Raw Normal View History

2020-04-05 13:25:47 +00:00
__filename__ = "tests.py"
__author__ = "Bob Mottram"
__license__ = "AGPL3+"
2021-01-26 10:07:42 +00:00
__version__ = "1.2.0"
2020-04-05 13:25:47 +00:00
__maintainer__ = "Bob Mottram"
__email__ = "bob@freedombone.net"
__status__ = "Production"
2019-06-30 20:14:03 +00:00
import time
2020-04-05 13:25:47 +00:00
import os
2019-06-30 21:20:02 +00:00
import shutil
2019-08-16 10:36:41 +00:00
import json
2019-08-15 18:21:43 +00:00
from time import gmtime, strftime
2019-07-09 14:20:23 +00:00
from pprint import pprint
2019-06-30 20:14:03 +00:00
from httpsig import signPostHeaders
from httpsig import signPostHeadersNew
2019-06-30 20:14:03 +00:00
from httpsig import verifyPostHeaders
from httpsig import messageContentDigest
2019-06-30 20:14:03 +00:00
from cache import storePersonInCache
from cache import getPersonFromCache
from threads import threadWithTrace
2019-06-30 21:20:02 +00:00
from daemon import runDaemon
from session import createSession
2020-12-13 19:05:26 +00:00
from posts import getMentionedPeople
2020-08-25 19:35:55 +00:00
from posts import validContentWarning
2019-06-30 21:20:02 +00:00
from posts import deleteAllPosts
from posts import createPublicPost
2019-06-30 22:56:37 +00:00
from posts import sendPost
2019-07-05 14:39:24 +00:00
from posts import noOfFollowersOnDomain
from posts import groupFollowersByDomain
2019-07-12 22:29:10 +00:00
from posts import archivePostsForPerson
2019-07-16 10:19:04 +00:00
from posts import sendPostViaServer
2019-07-01 11:09:09 +00:00
from follow import clearFollows
from follow import clearFollowers
2019-07-16 21:38:06 +00:00
from follow import sendFollowRequestViaServer
2019-07-17 11:54:13 +00:00
from follow import sendUnfollowRequestViaServer
from utils import camelCaseSplit
from utils import decodedHost
2020-12-16 11:19:16 +00:00
from utils import getFullDomain
2020-11-24 10:53:10 +00:00
from utils import validNickname
2020-11-08 11:24:43 +00:00
from utils import firstParagraphFromString
2020-08-23 11:13:35 +00:00
from utils import removeIdEnding
from siteactive import siteIsActive
from utils import updateRecentPostsCache
2019-07-06 19:24:52 +00:00
from utils import followPerson
2019-08-21 16:35:46 +00:00
from utils import getNicknameFromActor
from utils import getDomainFromActor
2019-09-29 18:48:34 +00:00
from utils import copytree
from utils import loadJson
from utils import saveJson
2019-10-12 12:45:53 +00:00
from utils import getStatusNumber
2020-09-25 13:21:56 +00:00
from utils import getFollowersOfPerson
from utils import removeHtml
from utils import dangerousMarkup
2021-03-12 12:04:34 +00:00
from pgp import extractPGPPublicKey
from utils import containsPGPPublicKey
2019-06-30 21:20:02 +00:00
from follow import followerOfPerson
2020-12-22 13:57:24 +00:00
from follow import unfollowAccount
from follow import unfollowerOfAccount
2019-07-06 13:49:25 +00:00
from follow import sendFollowRequest
2019-07-03 10:04:23 +00:00
from person import createPerson
from person import setDisplayNickname
2019-07-03 10:04:23 +00:00
from person import setBio
2020-06-15 12:37:53 +00:00
# from person import generateRSAKey
2019-07-19 10:01:24 +00:00
from skills import setSkillLevel
2019-07-18 15:09:23 +00:00
from roles import setRole
2019-07-18 16:21:26 +00:00
from roles import outboxDelegate
from auth import constantTimeStringCheck
2019-07-03 18:24:44 +00:00
from auth import createBasicAuthHeader
from auth import authorizeBasic
from auth import storeBasicCredentials
2019-07-11 12:29:31 +00:00
from like import likePost
from like import sendLikeViaServer
2019-07-11 17:55:10 +00:00
from announce import announcePublic
2019-07-16 19:07:45 +00:00
from announce import sendAnnounceViaServer
2019-07-12 19:26:54 +00:00
from media import getMediaPath
2019-08-30 15:50:20 +00:00
from media import getAttachmentMediaType
2019-07-17 17:16:48 +00:00
from delete import sendDeleteViaServer
2020-08-21 18:32:16 +00:00
from inbox import jsonPostAllowsComments
from inbox import validInbox
2019-07-18 11:35:48 +00:00
from inbox import validInboxFilenames
2020-12-22 13:57:24 +00:00
from categories import guessHashtagCategory
from content import extractTextFieldsInPOST
from content import validHashTag
from content import htmlReplaceEmailQuote
2020-08-02 17:01:12 +00:00
from content import htmlReplaceQuoteMarks
2020-12-13 14:48:45 +00:00
from content import dangerousCSS
2019-09-01 08:55:05 +00:00
from content import addWebLinks
2019-09-29 18:48:34 +00:00
from content import replaceEmojiFromTags
from content import addHtmlTags
2019-11-04 20:39:14 +00:00
from content import removeLongWords
2020-05-12 09:34:58 +00:00
from content import replaceContentDuplicates
from content import removeTextFormatting
2020-10-11 09:33:31 +00:00
from content import removeHtmlTag
2019-11-23 13:04:11 +00:00
from theme import setCSSparam
from linked_data_sig import generateJsonSignature
from linked_data_sig import verifyJsonSignature
2020-10-17 12:05:41 +00:00
from newsdaemon import hashtagRuleTree
2020-10-17 17:36:10 +00:00
from newsdaemon import hashtagRuleResolve
2020-10-25 10:06:54 +00:00
from newswire import getNewswireTags
2020-11-22 18:43:01 +00:00
from newswire import parseFeedDate
2021-01-22 13:32:37 +00:00
from mastoapiv1 import getMastoApiV1IdFromNickname
from mastoapiv1 import getNicknameFromMastoApiV1Id
2021-02-02 21:08:33 +00:00
from webapp_post import prepareHtmlPostNickname
2021-02-24 20:37:59 +00:00
from webapp_utils import markdownToHtml
from speaker import speakerReplaceLinks
2019-06-30 20:14:03 +00:00
2020-04-05 13:25:47 +00:00
testServerAliceRunning = False
testServerBobRunning = False
testServerEveRunning = False
thrAlice = None
thrBob = None
thrEve = None
2019-06-30 21:27:25 +00:00
def testHttpSigNew():
print('testHttpSigNew')
messageBodyJson = {"hello": "world"}
messageBodyJsonStr = json.dumps(messageBodyJson)
publicKeyPem = \
'-----BEGIN RSA PUBLIC KEY-----\n' + \
'MIIBCgKCAQEAhAKYdtoeoy8zcAcR874L8' + \
'cnZxKzAGwd7v36APp7Pv6Q2jdsPBRrw\n' + \
'WEBnez6d0UDKDwGbc6nxfEXAy5mbhgajz' + \
'rw3MOEt8uA5txSKobBpKDeBLOsdJKFq\n' + \
'MGmXCQvEG7YemcxDTRPxAleIAgYYRjTSd' + \
'/QBwVW9OwNFhekro3RtlinV0a75jfZg\n' + \
'kne/YiktSvLG34lw2zqXBDTC5NHROUqGT' + \
'lML4PlNZS5Ri2U4aCNx2rUPRcKIlE0P\n' + \
'uKxI4T+HIaFpv8+rdV6eUgOrB2xeI1dSF' + \
'Fn/nnv5OoZJEIB+VmuKn3DCUcCZSFlQ\n' + \
'PSXSfBDiUGhwOw76WuSSsf1D4b/vLoJ10wIDAQAB\n' + \
'-----END RSA PUBLIC KEY-----\n'
privateKeyPem = \
'-----BEGIN RSA PRIVATE KEY-----\n' + \
'MIIEqAIBAAKCAQEAhAKYdtoeoy8zcAcR8' + \
'74L8cnZxKzAGwd7v36APp7Pv6Q2jdsP\n' + \
'BRrwWEBnez6d0UDKDwGbc6nxfEXAy5mbh' + \
'gajzrw3MOEt8uA5txSKobBpKDeBLOsd\n' + \
'JKFqMGmXCQvEG7YemcxDTRPxAleIAgYYR' + \
'jTSd/QBwVW9OwNFhekro3RtlinV0a75\n' + \
'jfZgkne/YiktSvLG34lw2zqXBDTC5NHRO' + \
'UqGTlML4PlNZS5Ri2U4aCNx2rUPRcKI\n' + \
'lE0PuKxI4T+HIaFpv8+rdV6eUgOrB2xeI' + \
'1dSFFn/nnv5OoZJEIB+VmuKn3DCUcCZ\n' + \
'SFlQPSXSfBDiUGhwOw76WuSSsf1D4b/vL' + \
'oJ10wIDAQABAoIBAG/JZuSWdoVHbi56\n' + \
'vjgCgkjg3lkO1KrO3nrdm6nrgA9P9qaPj' + \
'xuKoWaKO1cBQlE1pSWp/cKncYgD5WxE\n' + \
'CpAnRUXG2pG4zdkzCYzAh1i+c34L6oZoH' + \
'sirK6oNcEnHveydfzJL5934egm6p8DW\n' + \
'+m1RQ70yUt4uRc0YSor+q1LGJvGQHReF0' + \
'WmJBZHrhz5e63Pq7lE0gIwuBqL8SMaA\n' + \
'yRXtK+JGxZpImTq+NHvEWWCu09SCq0r83' + \
'8ceQI55SvzmTkwqtC+8AT2zFviMZkKR\n' + \
'Qo6SPsrqItxZWRty2izawTF0Bf5S2VAx7' + \
'O+6t3wBsQ1sLptoSgX3QblELY5asI0J\n' + \
'YFz7LJECgYkAsqeUJmqXE3LP8tYoIjMIA' + \
'KiTm9o6psPlc8CrLI9CH0UbuaA2JCOM\n' + \
'cCNq8SyYbTqgnWlB9ZfcAm/cFpA8tYci9' + \
'm5vYK8HNxQr+8FS3Qo8N9RJ8d0U5Csw\n' + \
'DzMYfRghAfUGwmlWj5hp1pQzAuhwbOXFt' + \
'xKHVsMPhz1IBtF9Y8jvgqgYHLbmyiu1\n' + \
'mwJ5AL0pYF0G7x81prlARURwHo0Yf52kE' + \
'w1dxpx+JXER7hQRWQki5/NsUEtv+8RT\n' + \
'qn2m6qte5DXLyn83b1qRscSdnCCwKtKWU' + \
'ug5q2ZbwVOCJCtmRwmnP131lWRYfj67\n' + \
'B/xJ1ZA6X3GEf4sNReNAtaucPEelgR2ns' + \
'N0gKQKBiGoqHWbK1qYvBxX2X3kbPDkv\n' + \
'9C+celgZd2PW7aGYLCHq7nPbmfDV0yHcW' + \
'jOhXZ8jRMjmANVR/eLQ2EfsRLdW69bn\n' + \
'f3ZD7JS1fwGnO3exGmHO3HZG+6AvberKY' + \
'VYNHahNFEw5TsAcQWDLRpkGybBcxqZo\n' + \
'81YCqlqidwfeO5YtlO7etx1xLyqa2NsCe' + \
'G9A86UjG+aeNnXEIDk1PDK+EuiThIUa\n' + \
'/2IxKzJKWl1BKr2d4xAfR0ZnEYuRrbeDQ' + \
'YgTImOlfW6/GuYIxKYgEKCFHFqJATAG\n' + \
'IxHrq1PDOiSwXd2GmVVYyEmhZnbcp8Cxa' + \
'EMQoevxAta0ssMK3w6UsDtvUvYvF22m\n' + \
'qQKBiD5GwESzsFPy3Ga0MvZpn3D6EJQLg' + \
'snrtUPZx+z2Ep2x0xc5orneB5fGyF1P\n' + \
'WtP+fG5Q6Dpdz3LRfm+KwBCWFKQjg7uTx' + \
'cjerhBWEYPmEMKYwTJF5PBG9/ddvHLQ\n' + \
'EQeNC8fHGg4UXU8mhHnSBt3EA10qQJfRD' + \
's15M38eG2cYwB1PZpDHScDnDA0=\n' + \
'-----END RSA PRIVATE KEY-----'
sigInput = \
'sig1=(date); alg=rsa-sha256; keyId="test-key-b"'
sig = \
'sig1=:HtXycCl97RBVkZi66ADKnC9c5eSSlb57GnQ4KFqNZplOpNfxqk62' + \
'JzZ484jXgLvoOTRaKfR4hwyxlcyb+BWkVasApQovBSdit9Ml/YmN2IvJDPncrlhPD' + \
'VDv36Z9/DiSO+RNHD7iLXugdXo1+MGRimW1RmYdenl/ITeb7rjfLZ4b9VNnLFtVWw' + \
'rjhAiwIqeLjodVImzVc5srrk19HMZNuUejK6I3/MyN3+3U8tIRW4LWzx6ZgGZUaEE' + \
'P0aBlBkt7Fj0Tt5/P5HNW/Sa/m8smxbOHnwzAJDa10PyjzdIbywlnWIIWtZKPPsoV' + \
'oKVopUWEU3TNhpWmaVhFrUL/O6SN3w==:'
# "hs2019", using RSASSA-PSS [RFC8017] and SHA-512 [RFC6234]
# sigInput = \
# 'sig1=(*request-target, *created, host, date, ' + \
# 'cache-control, x-empty-header, x-example); keyId="test-key-a"; ' + \
# 'alg=hs2019; created=1402170695; expires=1402170995'
# sig = \
# 'sig1=:K2qGT5srn2OGbOIDzQ6kYT+ruaycnDAAUpKv+ePFfD0RAxn/1BUe' + \
# 'Zx/Kdrq32DrfakQ6bPsvB9aqZqognNT6be4olHROIkeV879RrsrObury8L9SCEibe' + \
# 'oHyqU/yCjphSmEdd7WD+zrchK57quskKwRefy2iEC5S2uAH0EPyOZKWlvbKmKu5q4' + \
# 'CaB8X/I5/+HLZLGvDiezqi6/7p2Gngf5hwZ0lSdy39vyNMaaAT0tKo6nuVw0S1MVg' + \
# '1Q7MpWYZs0soHjttq0uLIA3DIbQfLiIvK6/l0BdWTU7+2uQj7lBkQAsFZHoA96ZZg' + \
# 'FquQrXRlmYOh+Hx5D9fJkXcXe5tmAg==:'
nickname = 'foo'
boxpath = '/' + nickname
# headers = {
# "*request-target": "get " + boxpath,
# "*created": "1402170695",
# "host": "example.org",
# "date": "Tue, 07 Jun 2014 20:51:35 GMT",
# "cache-control": "max-age=60, must-revalidate",
# "x-emptyheader": "",
# "x-example": "Example header with some whitespace.",
# "x-dictionary": "b=2",
# "x-dictionary": "a=1",
# "x-list": "(a, b, c)",
# "Signature-Input": sigInput,
# "Signature": sig
# }
dateStr = "Tue, 07 Jun 2014 20:51:35 GMT"
2021-02-22 18:27:04 +00:00
secondsSinceEpoch = 1402170695
domain = "example.com"
port = 443
headers = {
2021-02-22 18:27:04 +00:00
"*created": str(secondsSinceEpoch),
"*request-target": "post /foo?param=value&pet=dog",
"host": domain,
"date": dateStr,
"content-type": "application/json",
"digest": "SHA-256=X48E9qOokqqrvdts8nOJRJN3OWDUoyWxBf7kbu9DBPE=",
"content-length": "18",
"Signature-Input": sigInput,
"Signature": sig
}
httpPrefix = 'https'
debug = False
assert verifyPostHeaders(httpPrefix, publicKeyPem, headers,
boxpath, False, None,
messageBodyJsonStr, debug,
True)
# make a deliberate mistake
headers['Signature'] = headers['Signature'].replace('V', 'B')
assert not verifyPostHeaders(httpPrefix, publicKeyPem, headers,
boxpath, False, None,
messageBodyJsonStr, debug,
True)
# test signing
bodyDigest = messageContentDigest(messageBodyJsonStr)
contentLength = len(messageBodyJsonStr)
headers = {
"host": domain,
"date": dateStr,
"digest": f'SHA-256={bodyDigest}',
"content-type": "application/json",
"content-length": str(contentLength)
}
signatureIndexHeader, signatureHeader = \
signPostHeadersNew(dateStr, privateKeyPem, nickname,
domain, port,
domain, port,
boxpath, httpPrefix, messageBodyJsonStr,
'rsa-sha256')
assert signatureIndexHeader == \
'keyId="https://example.com/users/foo#main-key"; ' + \
2021-02-22 18:27:04 +00:00
'alg=hs2019; created=' + str(secondsSinceEpoch) + '; ' + \
'sig1=(*request-target, *created, host, date, ' + \
'digest, content-type, content-length)'
assert signatureHeader == \
'sig1=:LQU1PcJILSp1Q30GWINusfftYYKfTtam7InSu2c+ZzfGC' + \
'bTSevRgifZFuG2asFi8ubG/uUVHiBwIxxIz1u/JyWC3lYIFgjQF' + \
'RFM6As2b/ytnMA0LQhNebvk05iUNsz5izSoNTp5h9J7+roWkl6l' + \
'8d5EA7vPMTQTJZnyU1cXBlvP1MtuVAKR6MbB3Aa/iZ4XOeaNK5E' + \
'1VuPfNFrdnizIELE3nGVoVqNNImgMY3DWhtF3vvezrcT0J2vNGZ' + \
'cvhBfgn/xeAsNxz67SIHMgiXvLL6TFqEI1en9dl9A3ihB6ZO6+W' + \
'gUoW7OobZNlPxAUkQCc2A6oVjCYOdpKdrMAXQp2TQQ==:'
def _testHttpsigBase(withDigest):
2019-06-30 20:14:03 +00:00
print('testHttpsig(' + str(withDigest) + ')')
2019-08-09 09:46:33 +00:00
2020-04-05 13:25:47 +00:00
baseDir = os.getcwd()
path = baseDir + '/.testHttpsigBase'
2019-08-09 09:46:33 +00:00
if os.path.isdir(path):
shutil.rmtree(path)
os.mkdir(path)
os.chdir(path)
2020-04-05 13:25:47 +00:00
contentType = 'application/activity+json'
nickname = 'socrates'
domain = 'argumentative.social'
httpPrefix = 'https'
port = 5576
password = 'SuperSecretPassword'
privateKeyPem, publicKeyPem, person, wfEndpoint = \
2020-07-12 12:31:28 +00:00
createPerson(path, nickname, domain, port, httpPrefix,
False, False, password)
2019-08-09 09:46:33 +00:00
assert privateKeyPem
2020-04-05 13:25:47 +00:00
messageBodyJson = {
2020-03-22 20:36:19 +00:00
"a key": "a value",
"another key": "A string",
"yet another key": "Another string"
}
2020-04-05 13:25:47 +00:00
messageBodyJsonStr = json.dumps(messageBodyJson)
2019-07-01 09:31:02 +00:00
2020-12-16 11:19:16 +00:00
headersDomain = getFullDomain(domain, port)
2019-07-01 09:31:02 +00:00
2020-04-05 13:25:47 +00:00
dateStr = strftime("%a, %d %b %Y %H:%M:%S %Z", gmtime())
boxpath = '/inbox'
2019-06-30 20:14:03 +00:00
if not withDigest:
2020-04-05 13:25:47 +00:00
headers = {
2020-03-22 20:36:19 +00:00
'host': headersDomain,
'date': dateStr,
'content-type': 'application/json'
}
2020-04-05 13:25:47 +00:00
signatureHeader = \
signPostHeaders(dateStr, privateKeyPem, nickname,
domain, port,
domain, port,
2019-08-16 13:47:01 +00:00
boxpath, httpPrefix, None)
2019-06-30 20:14:03 +00:00
else:
2020-04-05 13:25:47 +00:00
bodyDigest = messageContentDigest(messageBodyJsonStr)
contentLength = len(messageBodyJsonStr)
headers = {
2020-03-22 20:36:19 +00:00
'host': headersDomain,
'date': dateStr,
'digest': f'SHA-256={bodyDigest}',
'content-type': contentType,
'content-length': str(contentLength)
}
2020-04-05 13:25:47 +00:00
signatureHeader = \
signPostHeaders(dateStr, privateKeyPem, nickname,
domain, port,
domain, port,
boxpath, httpPrefix, messageBodyJsonStr)
2019-07-01 09:31:02 +00:00
2020-04-05 13:25:47 +00:00
headers['signature'] = signatureHeader
assert verifyPostHeaders(httpPrefix, publicKeyPem, headers,
boxpath, False, None,
messageBodyJsonStr, False)
2019-11-12 18:21:52 +00:00
if withDigest:
# everything correct except for content-length
2020-04-05 13:25:47 +00:00
headers['content-length'] = str(contentLength + 2)
assert verifyPostHeaders(httpPrefix, publicKeyPem, headers,
boxpath, False, None,
messageBodyJsonStr, False) is False
assert verifyPostHeaders(httpPrefix, publicKeyPem, headers,
'/parambulator' + boxpath, False, None,
messageBodyJsonStr, False) is False
assert verifyPostHeaders(httpPrefix, publicKeyPem, headers,
boxpath, True, None,
messageBodyJsonStr, False) is False
2019-06-30 20:14:03 +00:00
if not withDigest:
# fake domain
2020-04-05 13:25:47 +00:00
headers = {
2020-03-22 20:36:19 +00:00
'host': 'bogon.domain',
'date': dateStr,
'content-type': 'application/json'
}
2019-06-30 20:14:03 +00:00
else:
# correct domain but fake message
2020-04-05 13:25:47 +00:00
messageBodyJsonStr = \
'{"a key": "a value", "another key": "Fake GNUs", ' + \
'"yet another key": "More Fake GNUs"}'
contentLength = len(messageBodyJsonStr)
bodyDigest = messageContentDigest(messageBodyJsonStr)
headers = {
2020-03-22 20:36:19 +00:00
'host': domain,
'date': dateStr,
'digest': f'SHA-256={bodyDigest}',
'content-type': contentType,
'content-length': str(contentLength)
}
2020-04-05 13:25:47 +00:00
headers['signature'] = signatureHeader
assert verifyPostHeaders(httpPrefix, publicKeyPem, headers,
boxpath, True, None,
messageBodyJsonStr, False) is False
2019-11-12 18:21:52 +00:00
2019-08-09 09:46:33 +00:00
os.chdir(baseDir)
shutil.rmtree(path)
2019-06-30 20:14:03 +00:00
2020-04-05 13:25:47 +00:00
2019-06-30 20:14:03 +00:00
def testHttpsig():
_testHttpsigBase(True)
_testHttpsigBase(False)
2019-06-30 20:14:03 +00:00
2020-04-05 13:25:47 +00:00
2019-06-30 20:14:03 +00:00
def testCache():
print('testCache')
2020-04-05 13:25:47 +00:00
personUrl = "cat@cardboard.box"
personJson = {
"id": 123456,
"test": "This is a test"
}
personCache = {}
storePersonInCache(None, personUrl, personJson, personCache, True)
result = getPersonFromCache(None, personUrl, personCache, True)
2020-04-05 13:25:47 +00:00
assert result['id'] == 123456
assert result['test'] == 'This is a test'
2019-06-30 20:14:03 +00:00
def testThreadsFunction(param: str):
for i in range(10000):
time.sleep(2)
2020-04-05 13:25:47 +00:00
2019-06-30 20:14:03 +00:00
def testThreads():
print('testThreads')
2020-04-05 13:25:47 +00:00
thr = \
threadWithTrace(target=testThreadsFunction,
args=('test',),
daemon=True)
2019-06-30 20:14:03 +00:00
thr.start()
2020-12-18 15:29:12 +00:00
assert thr.is_alive() is True
2019-06-30 20:14:03 +00:00
time.sleep(1)
thr.kill()
thr.join()
2020-12-18 15:29:12 +00:00
assert thr.is_alive() is False
2019-06-30 21:20:02 +00:00
2020-04-05 13:25:47 +00:00
def createServerAlice(path: str, domain: str, port: int,
bobAddress: str, federationList: [],
hasFollows: bool, hasPosts: bool,
2020-09-27 19:27:24 +00:00
sendThreads: []):
2020-04-05 13:25:47 +00:00
print('Creating test server: Alice on port ' + str(port))
2019-06-30 21:20:02 +00:00
if os.path.isdir(path):
shutil.rmtree(path)
os.mkdir(path)
os.chdir(path)
2020-04-05 13:25:47 +00:00
nickname = 'alice'
httpPrefix = 'http'
2020-06-09 11:03:59 +00:00
proxyType = None
2020-04-05 13:25:47 +00:00
password = 'alicepass'
maxReplies = 64
domainMaxPostsPerDay = 1000
accountMaxPostsPerDay = 1000
allowDeletion = True
privateKeyPem, publicKeyPem, person, wfEndpoint = \
2020-07-12 12:31:28 +00:00
createPerson(path, nickname, domain, port, httpPrefix, True,
False, password)
2020-04-05 13:25:47 +00:00
deleteAllPosts(path, nickname, domain, 'inbox')
deleteAllPosts(path, nickname, domain, 'outbox')
assert setSkillLevel(path, nickname, domain, 'hacking', 90)
assert setRole(path, nickname, domain, 'someproject', 'guru')
2019-07-06 13:49:25 +00:00
if hasFollows:
2020-04-05 13:25:47 +00:00
followPerson(path, nickname, domain, 'bob', bobAddress,
federationList, False)
followerOfPerson(path, nickname, domain, 'bob', bobAddress,
federationList, False)
2019-07-06 13:49:25 +00:00
if hasPosts:
testFollowersOnly = False
testSaveToFile = True
2020-12-22 21:27:46 +00:00
clientToServer = False
testCommentsEnabled = True
testAttachImageFilename = None
testMediaType = None
testImageDescription = None
2020-04-05 13:25:47 +00:00
createPublicPost(path, nickname, domain, port, httpPrefix,
"No wise fish would go anywhere without a porpoise",
testFollowersOnly,
testSaveToFile,
clientToServer,
testCommentsEnabled,
testAttachImageFilename,
testMediaType,
testImageDescription)
2020-04-05 13:25:47 +00:00
createPublicPost(path, nickname, domain, port, httpPrefix,
"Curiouser and curiouser!",
testFollowersOnly,
testSaveToFile,
clientToServer,
testCommentsEnabled,
testAttachImageFilename,
testMediaType,
testImageDescription)
2020-04-05 13:25:47 +00:00
createPublicPost(path, nickname, domain, port, httpPrefix,
"In the gardens of memory, in the palace " +
"of dreams, that is where you and I shall meet",
testFollowersOnly,
testSaveToFile,
clientToServer,
testCommentsEnabled,
testAttachImageFilename,
testMediaType,
testImageDescription)
2019-06-30 21:27:25 +00:00
global testServerAliceRunning
2020-04-05 13:25:47 +00:00
testServerAliceRunning = True
maxMentions = 10
maxEmoji = 10
onionDomain = None
i2pDomain = None
allowLocalNetworkAccess = True
maxNewswirePosts = 20
dormantMonths = 3
sendThreadsTimeoutMins = 30
maxFollowers = 10
verifyAllSignatures = True
2021-02-15 22:06:53 +00:00
brochMode = False
2019-06-30 21:20:02 +00:00
print('Server running: Alice')
2021-02-15 22:06:53 +00:00
runDaemon(brochMode,
verifyAllSignatures,
sendThreadsTimeoutMins,
dormantMonths, maxNewswirePosts,
allowLocalNetworkAccess,
2048, False, True, False, False, True, maxFollowers,
0, 100, 1024, 5, False,
0, False, 1, False, False, False,
2020-10-07 09:10:42 +00:00
5, True, True, 'en', __version__,
"instanceId", False, path, domain,
onionDomain, i2pDomain, None, port, port,
2020-04-05 13:25:47 +00:00
httpPrefix, federationList, maxMentions, maxEmoji, False,
2020-06-09 11:03:59 +00:00
proxyType, maxReplies,
2020-04-05 13:25:47 +00:00
domainMaxPostsPerDay, accountMaxPostsPerDay,
allowDeletion, True, True, False, sendThreads,
2020-07-12 12:31:28 +00:00
False)
2020-04-05 13:25:47 +00:00
def createServerBob(path: str, domain: str, port: int,
aliceAddress: str, federationList: [],
hasFollows: bool, hasPosts: bool,
2020-09-27 19:27:24 +00:00
sendThreads: []):
2020-04-05 13:25:47 +00:00
print('Creating test server: Bob on port ' + str(port))
2019-06-30 21:20:02 +00:00
if os.path.isdir(path):
shutil.rmtree(path)
os.mkdir(path)
os.chdir(path)
2020-04-05 13:25:47 +00:00
nickname = 'bob'
httpPrefix = 'http'
2020-06-09 11:03:59 +00:00
proxyType = None
2020-04-05 13:25:47 +00:00
clientToServer = False
password = 'bobpass'
maxReplies = 64
domainMaxPostsPerDay = 1000
accountMaxPostsPerDay = 1000
allowDeletion = True
privateKeyPem, publicKeyPem, person, wfEndpoint = \
2020-07-12 12:31:28 +00:00
createPerson(path, nickname, domain, port, httpPrefix, True,
False, password)
2020-04-05 13:25:47 +00:00
deleteAllPosts(path, nickname, domain, 'inbox')
deleteAllPosts(path, nickname, domain, 'outbox')
assert setRole(path, nickname, domain, 'bandname', 'bass player')
assert setRole(path, nickname, domain, 'bandname', 'publicist')
2019-07-06 13:49:25 +00:00
if hasFollows:
2020-04-05 13:25:47 +00:00
followPerson(path, nickname, domain,
'alice', aliceAddress, federationList, False)
followerOfPerson(path, nickname, domain,
'alice', aliceAddress, federationList, False)
2019-07-06 13:49:25 +00:00
if hasPosts:
testFollowersOnly = False
testSaveToFile = True
testCommentsEnabled = True
testAttachImageFilename = None
2020-12-22 21:27:46 +00:00
testImageDescription = None
testMediaType = None
2020-04-05 13:25:47 +00:00
createPublicPost(path, nickname, domain, port, httpPrefix,
"It's your life, live it your way.",
testFollowersOnly,
testSaveToFile,
clientToServer,
testCommentsEnabled,
testAttachImageFilename,
testMediaType,
testImageDescription)
2020-04-05 13:25:47 +00:00
createPublicPost(path, nickname, domain, port, httpPrefix,
"One of the things I've realised is that " +
"I am very simple",
testFollowersOnly,
testSaveToFile,
clientToServer,
testCommentsEnabled,
testAttachImageFilename,
testMediaType,
testImageDescription)
2020-04-05 13:25:47 +00:00
createPublicPost(path, nickname, domain, port, httpPrefix,
"Quantum physics is a bit of a passion of mine",
testFollowersOnly,
testSaveToFile,
clientToServer,
testCommentsEnabled,
testAttachImageFilename,
testMediaType,
testImageDescription)
2019-06-30 21:27:25 +00:00
global testServerBobRunning
2020-04-05 13:25:47 +00:00
testServerBobRunning = True
maxMentions = 10
maxEmoji = 10
onionDomain = None
i2pDomain = None
allowLocalNetworkAccess = True
maxNewswirePosts = 20
dormantMonths = 3
sendThreadsTimeoutMins = 30
maxFollowers = 10
verifyAllSignatures = True
2021-02-15 22:06:53 +00:00
brochMode = False
2019-06-30 21:20:02 +00:00
print('Server running: Bob')
2021-02-15 22:06:53 +00:00
runDaemon(brochMode,
verifyAllSignatures,
sendThreadsTimeoutMins,
dormantMonths, maxNewswirePosts,
allowLocalNetworkAccess,
2048, False, True, False, False, True, maxFollowers,
0, 100, 1024, 5, False, 0,
False, 1, False, False, False,
2020-10-07 09:10:42 +00:00
5, True, True, 'en', __version__,
"instanceId", False, path, domain,
onionDomain, i2pDomain, None, port, port,
2020-04-05 13:25:47 +00:00
httpPrefix, federationList, maxMentions, maxEmoji, False,
2020-06-09 11:03:59 +00:00
proxyType, maxReplies,
2020-04-05 13:25:47 +00:00
domainMaxPostsPerDay, accountMaxPostsPerDay,
allowDeletion, True, True, False, sendThreads,
2020-07-12 12:31:28 +00:00
False)
2020-04-05 13:25:47 +00:00
def createServerEve(path: str, domain: str, port: int, federationList: [],
hasFollows: bool, hasPosts: bool,
2020-09-27 19:27:24 +00:00
sendThreads: []):
2020-04-05 13:25:47 +00:00
print('Creating test server: Eve on port ' + str(port))
if os.path.isdir(path):
shutil.rmtree(path)
os.mkdir(path)
os.chdir(path)
2020-04-05 13:25:47 +00:00
nickname = 'eve'
httpPrefix = 'http'
2020-06-09 11:03:59 +00:00
proxyType = None
2020-04-05 13:25:47 +00:00
password = 'evepass'
maxReplies = 64
allowDeletion = True
privateKeyPem, publicKeyPem, person, wfEndpoint = \
2020-07-12 12:31:28 +00:00
createPerson(path, nickname, domain, port, httpPrefix, True,
False, password)
2020-04-05 13:25:47 +00:00
deleteAllPosts(path, nickname, domain, 'inbox')
deleteAllPosts(path, nickname, domain, 'outbox')
global testServerEveRunning
2020-04-05 13:25:47 +00:00
testServerEveRunning = True
maxMentions = 10
maxEmoji = 10
onionDomain = None
i2pDomain = None
allowLocalNetworkAccess = True
maxNewswirePosts = 20
dormantMonths = 3
sendThreadsTimeoutMins = 30
maxFollowers = 10
verifyAllSignatures = True
2021-02-15 22:06:53 +00:00
brochMode = False
print('Server running: Eve')
2021-02-15 22:06:53 +00:00
runDaemon(brochMode,
verifyAllSignatures,
sendThreadsTimeoutMins,
dormantMonths, maxNewswirePosts,
allowLocalNetworkAccess,
2048, False, True, False, False, True, maxFollowers,
0, 100, 1024, 5, False, 0,
False, 1, False, False, False,
2020-10-07 09:10:42 +00:00
5, True, True, 'en', __version__,
"instanceId", False, path, domain,
onionDomain, i2pDomain, None, port, port,
2020-04-05 13:25:47 +00:00
httpPrefix, federationList, maxMentions, maxEmoji, False,
2020-06-09 11:03:59 +00:00
proxyType, maxReplies, allowDeletion, True, True, False,
sendThreads, False)
2020-04-05 13:25:47 +00:00
2019-06-30 21:20:02 +00:00
def testPostMessageBetweenServers():
print('Testing sending message from one server to the inbox of another')
2019-06-30 21:27:25 +00:00
global testServerAliceRunning
global testServerBobRunning
2020-04-05 13:25:47 +00:00
testServerAliceRunning = False
testServerBobRunning = False
2019-06-30 21:27:25 +00:00
2020-04-05 13:25:47 +00:00
httpPrefix = 'http'
2020-06-09 11:03:59 +00:00
proxyType = None
2019-06-30 22:56:37 +00:00
2020-04-05 13:25:47 +00:00
baseDir = os.getcwd()
if os.path.isdir(baseDir + '/.tests'):
shutil.rmtree(baseDir + '/.tests')
os.mkdir(baseDir + '/.tests')
2019-06-30 21:20:02 +00:00
# create the servers
2020-04-05 13:25:47 +00:00
aliceDir = baseDir + '/.tests/alice'
aliceDomain = '127.0.0.50'
alicePort = 61935
aliceAddress = aliceDomain + ':' + str(alicePort)
bobDir = baseDir + '/.tests/bob'
bobDomain = '127.0.0.100'
bobPort = 61936
federationList = [bobDomain, aliceDomain]
aliceSendThreads = []
bobSendThreads = []
bobAddress = bobDomain + ':' + str(bobPort)
2019-07-11 12:29:31 +00:00
2020-02-19 12:27:21 +00:00
global thrAlice
if thrAlice:
2020-12-18 15:29:12 +00:00
while thrAlice.is_alive():
2020-02-19 12:27:21 +00:00
thrAlice.stop()
time.sleep(1)
thrAlice.kill()
2020-04-05 13:25:47 +00:00
thrAlice = \
threadWithTrace(target=createServerAlice,
args=(aliceDir, aliceDomain, alicePort, bobAddress,
federationList, False, False,
2020-09-27 19:27:24 +00:00
aliceSendThreads),
2020-04-05 13:25:47 +00:00
daemon=True)
2020-02-19 12:27:21 +00:00
global thrBob
if thrBob:
2020-12-18 15:29:12 +00:00
while thrBob.is_alive():
2020-02-19 12:27:21 +00:00
thrBob.stop()
time.sleep(1)
thrBob.kill()
2020-04-05 13:25:47 +00:00
thrBob = \
threadWithTrace(target=createServerBob,
args=(bobDir, bobDomain, bobPort, aliceAddress,
federationList, False, False,
2020-09-27 19:27:24 +00:00
bobSendThreads),
2020-04-05 13:25:47 +00:00
daemon=True)
2019-07-01 21:01:43 +00:00
thrAlice.start()
2019-06-30 21:20:02 +00:00
thrBob.start()
2020-12-18 15:29:12 +00:00
assert thrAlice.is_alive() is True
assert thrBob.is_alive() is True
2019-06-30 21:20:02 +00:00
2019-06-30 21:27:25 +00:00
# wait for both servers to be running
while not (testServerAliceRunning and testServerBobRunning):
time.sleep(1)
2020-03-22 21:16:02 +00:00
2019-07-04 20:25:19 +00:00
time.sleep(1)
2019-06-30 21:20:02 +00:00
2019-07-11 12:29:31 +00:00
print('\n\n*******************************************************')
2019-06-30 22:56:37 +00:00
print('Alice sends to Bob')
os.chdir(aliceDir)
2020-06-09 11:03:59 +00:00
sessionAlice = createSession(proxyType)
2020-04-05 13:25:47 +00:00
inReplyTo = None
inReplyToAtomUri = None
subject = None
alicePostLog = []
followersOnly = False
saveToFile = True
clientToServer = False
ccUrl = None
alicePersonCache = {}
aliceCachedWebfingers = {}
attachedImageFilename = baseDir + '/img/logo.png'
mediaType = getAttachmentMediaType(attachedImageFilename)
attachedImageDescription = 'Logo'
isArticle = False
2019-07-11 12:29:31 +00:00
# nothing in Alice's outbox
2020-04-05 13:25:47 +00:00
outboxPath = aliceDir + '/accounts/alice@' + aliceDomain + '/outbox'
assert len([name for name in os.listdir(outboxPath)
if os.path.isfile(os.path.join(outboxPath, name))]) == 0
sendResult = \
sendPost(__version__,
sessionAlice, aliceDir, 'alice', aliceDomain, alicePort,
'bob', bobDomain, bobPort, ccUrl, httpPrefix,
'Why is a mouse when it spins? ' +
'यह एक परीक्षण है #sillyquestion',
followersOnly,
2020-08-21 17:40:50 +00:00
saveToFile, clientToServer, True,
attachedImageFilename, mediaType,
attachedImageDescription, federationList,
2020-04-05 13:25:47 +00:00
aliceSendThreads, alicePostLog, aliceCachedWebfingers,
alicePersonCache, isArticle, inReplyTo,
inReplyToAtomUri, subject)
print('sendResult: ' + str(sendResult))
queuePath = bobDir + '/accounts/bob@' + bobDomain + '/queue'
inboxPath = bobDir + '/accounts/bob@' + bobDomain + '/inbox'
mPath = getMediaPath()
mediaPath = aliceDir + '/' + mPath
2019-07-07 22:25:22 +00:00
for i in range(30):
2019-07-04 20:36:12 +00:00
if os.path.isdir(inboxPath):
2020-04-05 13:25:47 +00:00
if len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath, name))]) > 0:
if len([name for name in os.listdir(outboxPath)
if os.path.isfile(os.path.join(outboxPath,
name))]) == 1:
if len([name for name in os.listdir(mediaPath)
if os.path.isfile(os.path.join(mediaPath,
name))]) > 0:
if len([name for name in os.listdir(queuePath)
if os.path.isfile(os.path.join(queuePath,
name))]) == 0:
2019-10-19 17:50:05 +00:00
break
2019-07-01 21:01:43 +00:00
time.sleep(1)
2019-07-09 08:52:53 +00:00
2020-12-06 15:05:22 +00:00
# check that a news account exists
newsActorDir = aliceDir + '/accounts/news@' + aliceDomain
print("newsActorDir: " + newsActorDir)
assert os.path.isdir(newsActorDir)
newsActorFile = newsActorDir + '.json'
assert os.path.isfile(newsActorFile)
newsActorJson = loadJson(newsActorFile)
assert newsActorJson
assert newsActorJson.get("id")
# check the id of the news actor
print('News actor Id: ' + newsActorJson["id"])
assert (newsActorJson["id"] ==
httpPrefix + '://' + aliceAddress + '/users/news')
2019-07-12 19:26:54 +00:00
# Image attachment created
2020-04-05 13:25:47 +00:00
assert len([name for name in os.listdir(mediaPath)
if os.path.isfile(os.path.join(mediaPath, name))]) > 0
2019-07-11 12:29:31 +00:00
# inbox item created
2020-04-05 13:25:47 +00:00
assert len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath, name))]) == 1
2019-07-11 12:29:31 +00:00
# queue item removed
2020-04-05 13:25:47 +00:00
testval = len([name for name in os.listdir(queuePath)
if os.path.isfile(os.path.join(queuePath, name))])
print('queuePath: ' + queuePath + ' '+str(testval))
assert testval == 0
assert validInbox(bobDir, 'bob', bobDomain)
assert validInboxFilenames(bobDir, 'bob', bobDomain,
aliceDomain, alicePort)
2019-11-09 09:50:58 +00:00
print('Check that message received from Alice contains the expected text')
for name in os.listdir(inboxPath):
2020-04-05 13:25:47 +00:00
filename = os.path.join(inboxPath, name)
2019-11-09 09:50:58 +00:00
assert os.path.isfile(filename)
2020-04-05 13:25:47 +00:00
receivedJson = loadJson(filename, 0)
if receivedJson:
2019-11-09 09:50:58 +00:00
pprint(receivedJson['object']['content'])
2019-11-09 09:52:09 +00:00
assert receivedJson
2020-04-05 13:25:47 +00:00
assert 'Why is a mouse when it spins?' in \
receivedJson['object']['content']
2019-11-09 09:52:09 +00:00
assert 'यह एक परीक्षण है' in receivedJson['object']['content']
2019-07-11 12:59:00 +00:00
print('\n\n*******************************************************')
print("Bob likes Alice's post")
aliceDomainStr = aliceDomain + ':' + str(alicePort)
2020-04-05 13:25:47 +00:00
followerOfPerson(bobDir, 'bob', bobDomain, 'alice',
aliceDomainStr, federationList, False)
bobDomainStr = bobDomain + ':' + str(bobPort)
2020-04-05 13:25:47 +00:00
followPerson(aliceDir, 'alice', aliceDomain, 'bob',
bobDomainStr, federationList, False)
2020-04-05 13:25:47 +00:00
2020-06-09 11:03:59 +00:00
sessionBob = createSession(proxyType)
2020-04-05 13:25:47 +00:00
bobPostLog = []
bobPersonCache = {}
bobCachedWebfingers = {}
statusNumber = None
outboxPostFilename = None
outboxPath = aliceDir + '/accounts/alice@' + aliceDomain + '/outbox'
2019-07-11 12:59:00 +00:00
for name in os.listdir(outboxPath):
if '#statuses#' in name:
2020-04-05 13:25:47 +00:00
statusNumber = \
int(name.split('#statuses#')[1].replace('.json', ''))
outboxPostFilename = outboxPath + '/' + name
assert statusNumber > 0
2019-07-11 12:59:00 +00:00
assert outboxPostFilename
2020-04-05 13:25:47 +00:00
assert likePost({}, sessionBob, bobDir, federationList,
'bob', bobDomain, bobPort, httpPrefix,
'alice', aliceDomain, alicePort, [],
statusNumber, False, bobSendThreads, bobPostLog,
bobPersonCache, bobCachedWebfingers,
True, __version__)
2019-07-11 12:59:00 +00:00
for i in range(20):
if 'likes' in open(outboxPostFilename).read():
break
time.sleep(1)
2020-04-05 13:25:47 +00:00
alicePostJson = loadJson(outboxPostFilename, 0)
if alicePostJson:
2019-07-11 12:59:00 +00:00
pprint(alicePostJson)
2020-03-22 21:16:02 +00:00
2019-07-11 12:59:00 +00:00
assert 'likes' in open(outboxPostFilename).read()
2019-07-11 17:55:10 +00:00
print('\n\n*******************************************************')
print("Bob repeats Alice's post")
2020-04-05 13:25:47 +00:00
objectUrl = \
httpPrefix + '://' + aliceDomain + ':' + str(alicePort) + \
'/users/alice/statuses/' + str(statusNumber)
inboxPath = aliceDir + '/accounts/alice@' + aliceDomain + '/inbox'
outboxPath = bobDir + '/accounts/bob@' + bobDomain + '/outbox'
outboxBeforeAnnounceCount = \
len([name for name in os.listdir(outboxPath)
if os.path.isfile(os.path.join(outboxPath, name))])
beforeAnnounceCount = \
len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath, name))])
print('inbox items before announce: ' + str(beforeAnnounceCount))
print('outbox items before announce: ' + str(outboxBeforeAnnounceCount))
assert outboxBeforeAnnounceCount == 0
assert beforeAnnounceCount == 0
announcePublic(sessionBob, bobDir, federationList,
'bob', bobDomain, bobPort, httpPrefix,
objectUrl,
False, bobSendThreads, bobPostLog,
bobPersonCache, bobCachedWebfingers,
True, __version__)
announceMessageArrived = False
outboxMessageArrived = False
2019-07-11 19:31:02 +00:00
for i in range(10):
time.sleep(1)
2020-03-27 19:54:41 +00:00
if not os.path.isdir(inboxPath):
continue
2020-04-05 13:25:47 +00:00
if len([name for name in os.listdir(outboxPath)
if os.path.isfile(os.path.join(outboxPath, name))]) > 0:
outboxMessageArrived = True
2020-03-27 19:54:41 +00:00
print('Announce created by Bob')
2020-04-05 13:25:47 +00:00
if len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath, name))]) > 0:
announceMessageArrived = True
2020-03-27 19:54:41 +00:00
print('Announce message sent to Alice!')
if announceMessageArrived and outboxMessageArrived:
break
2020-04-05 13:25:47 +00:00
afterAnnounceCount = \
len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath, name))])
outboxAfterAnnounceCount = \
len([name for name in os.listdir(outboxPath)
if os.path.isfile(os.path.join(outboxPath, name))])
print('inbox items after announce: ' + str(afterAnnounceCount))
print('outbox items after announce: ' + str(outboxAfterAnnounceCount))
assert afterAnnounceCount == beforeAnnounceCount+1
assert outboxAfterAnnounceCount == outboxBeforeAnnounceCount + 1
2019-06-30 21:20:02 +00:00
# stop the servers
thrAlice.kill()
thrAlice.join()
2020-12-18 15:29:12 +00:00
assert thrAlice.is_alive() is False
2019-06-30 21:20:02 +00:00
thrBob.kill()
thrBob.join()
2020-12-18 15:29:12 +00:00
assert thrBob.is_alive() is False
2019-06-30 21:20:02 +00:00
os.chdir(baseDir)
shutil.rmtree(aliceDir)
shutil.rmtree(bobDir)
2020-04-05 13:25:47 +00:00
2019-10-15 09:31:10 +00:00
def testFollowBetweenServers():
print('Testing sending a follow request from one server to another')
global testServerAliceRunning
global testServerBobRunning
2020-04-05 13:25:47 +00:00
testServerAliceRunning = False
testServerBobRunning = False
2019-10-15 09:31:10 +00:00
2020-04-05 13:25:47 +00:00
httpPrefix = 'http'
2020-06-09 11:03:59 +00:00
proxyType = None
2020-04-05 13:25:47 +00:00
federationList = []
2019-10-15 09:31:10 +00:00
2020-04-05 13:25:47 +00:00
baseDir = os.getcwd()
if os.path.isdir(baseDir + '/.tests'):
shutil.rmtree(baseDir + '/.tests')
os.mkdir(baseDir + '/.tests')
2019-10-15 09:31:10 +00:00
# create the servers
2020-04-05 13:25:47 +00:00
aliceDir = baseDir + '/.tests/alice'
aliceDomain = '127.0.0.47'
alicePort = 61935
aliceSendThreads = []
aliceAddress = aliceDomain + ':' + str(alicePort)
bobDir = baseDir + '/.tests/bob'
bobDomain = '127.0.0.79'
bobPort = 61936
bobSendThreads = []
bobAddress = bobDomain + ':' + str(bobPort)
2020-02-19 12:27:21 +00:00
global thrAlice
if thrAlice:
2020-12-18 15:29:12 +00:00
while thrAlice.is_alive():
2020-02-19 12:27:21 +00:00
thrAlice.stop()
time.sleep(1)
thrAlice.kill()
2020-04-05 13:25:47 +00:00
thrAlice = \
threadWithTrace(target=createServerAlice,
args=(aliceDir, aliceDomain, alicePort, bobAddress,
federationList, False, False,
2020-09-27 19:27:24 +00:00
aliceSendThreads),
2020-04-05 13:25:47 +00:00
daemon=True)
2019-10-15 09:31:10 +00:00
2020-02-19 12:27:21 +00:00
global thrBob
if thrBob:
2020-12-18 15:29:12 +00:00
while thrBob.is_alive():
2020-02-19 12:27:21 +00:00
thrBob.stop()
time.sleep(1)
thrBob.kill()
2020-04-05 13:25:47 +00:00
thrBob = \
threadWithTrace(target=createServerBob,
args=(bobDir, bobDomain, bobPort, aliceAddress,
federationList, False, False,
2020-09-27 19:27:24 +00:00
bobSendThreads),
2020-04-05 13:25:47 +00:00
daemon=True)
2019-10-15 09:31:10 +00:00
thrAlice.start()
thrBob.start()
2020-12-18 15:29:12 +00:00
assert thrAlice.is_alive() is True
assert thrBob.is_alive() is True
2019-10-15 09:31:10 +00:00
# wait for all servers to be running
2020-04-05 13:25:47 +00:00
ctr = 0
2019-10-15 09:31:10 +00:00
while not (testServerAliceRunning and testServerBobRunning):
time.sleep(1)
2020-04-05 13:25:47 +00:00
ctr += 1
if ctr > 60:
2019-10-15 09:31:10 +00:00
break
2020-04-05 13:25:47 +00:00
print('Alice online: ' + str(testServerAliceRunning))
print('Bob online: ' + str(testServerBobRunning))
assert ctr <= 60
2019-10-15 09:31:10 +00:00
time.sleep(1)
# In the beginning all was calm and there were no follows
print('*********************************************************')
print('Alice sends a follow request to Bob')
os.chdir(aliceDir)
2020-06-09 11:03:59 +00:00
sessionAlice = createSession(proxyType)
2020-04-05 13:25:47 +00:00
inReplyTo = None
inReplyToAtomUri = None
subject = None
alicePostLog = []
followersOnly = False
saveToFile = True
clientToServer = False
ccUrl = None
alicePersonCache = {}
aliceCachedWebfingers = {}
alicePostLog = []
bobActor = httpPrefix + '://' + bobAddress + '/users/bob'
2020-04-05 13:25:47 +00:00
sendResult = \
sendFollowRequest(sessionAlice, aliceDir,
'alice', aliceDomain, alicePort, httpPrefix,
'bob', bobDomain, bobActor,
bobPort, httpPrefix,
2020-04-05 13:25:47 +00:00
clientToServer, federationList,
aliceSendThreads, alicePostLog,
aliceCachedWebfingers, alicePersonCache,
True, __version__)
2020-04-05 13:25:47 +00:00
print('sendResult: ' + str(sendResult))
2019-10-15 09:31:10 +00:00
2020-12-23 10:58:50 +00:00
for t in range(16):
2020-04-05 13:25:47 +00:00
if os.path.isfile(bobDir + '/accounts/bob@' +
bobDomain + '/followers.txt'):
if os.path.isfile(aliceDir + '/accounts/alice@' +
aliceDomain + '/following.txt'):
if os.path.isfile(aliceDir + '/accounts/alice@' +
aliceDomain + '/followingCalendar.txt'):
break
2019-10-15 09:31:10 +00:00
time.sleep(1)
2020-04-05 13:25:47 +00:00
assert validInbox(bobDir, 'bob', bobDomain)
assert validInboxFilenames(bobDir, 'bob', bobDomain,
aliceDomain, alicePort)
assert 'alice@' + aliceDomain in open(bobDir + '/accounts/bob@' +
bobDomain + '/followers.txt').read()
assert 'bob@' + bobDomain in open(aliceDir + '/accounts/alice@' +
aliceDomain + '/following.txt').read()
assert 'bob@' + bobDomain in open(aliceDir + '/accounts/alice@' +
aliceDomain +
'/followingCalendar.txt').read()
2019-10-15 09:31:10 +00:00
print('\n\n*********************************************************')
print('Alice sends a message to Bob')
2020-04-05 13:25:47 +00:00
alicePostLog = []
alicePersonCache = {}
aliceCachedWebfingers = {}
alicePostLog = []
isArticle = False
sendResult = \
sendPost(__version__,
sessionAlice, aliceDir, 'alice', aliceDomain, alicePort,
'bob', bobDomain, bobPort, ccUrl,
httpPrefix, 'Alice message', followersOnly, saveToFile,
2020-08-21 17:40:50 +00:00
clientToServer, True,
None, None, None, federationList,
2020-04-05 13:25:47 +00:00
aliceSendThreads, alicePostLog, aliceCachedWebfingers,
alicePersonCache, isArticle, inReplyTo,
inReplyToAtomUri, subject)
print('sendResult: ' + str(sendResult))
queuePath = bobDir + '/accounts/bob@' + bobDomain + '/queue'
inboxPath = bobDir + '/accounts/bob@' + bobDomain + '/inbox'
aliceMessageArrived = False
2019-10-15 09:31:10 +00:00
for i in range(20):
time.sleep(1)
if os.path.isdir(inboxPath):
2020-04-05 13:25:47 +00:00
if len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath, name))]) > 0:
aliceMessageArrived = True
2019-10-15 09:31:10 +00:00
print('Alice message sent to Bob!')
break
2020-04-05 13:25:47 +00:00
assert aliceMessageArrived is True
2019-10-15 09:31:10 +00:00
print('Message from Alice to Bob succeeded')
# stop the servers
thrAlice.kill()
thrAlice.join()
2020-12-18 15:29:12 +00:00
assert thrAlice.is_alive() is False
2019-10-15 09:31:10 +00:00
thrBob.kill()
thrBob.join()
2020-12-18 15:29:12 +00:00
assert thrBob.is_alive() is False
2020-03-22 21:16:02 +00:00
2019-07-09 08:52:53 +00:00
# queue item removed
2019-11-09 21:39:04 +00:00
time.sleep(4)
2020-04-05 13:25:47 +00:00
assert len([name for name in os.listdir(queuePath)
if os.path.isfile(os.path.join(queuePath, name))]) == 0
2020-03-22 21:16:02 +00:00
2019-07-06 13:49:25 +00:00
os.chdir(baseDir)
2020-04-05 13:25:47 +00:00
shutil.rmtree(baseDir + '/.tests')
2019-07-06 13:49:25 +00:00
def testFollowersOfPerson():
print('testFollowersOfPerson')
2020-04-05 13:25:47 +00:00
currDir = os.getcwd()
nickname = 'mxpop'
domain = 'diva.domain'
password = 'birb'
port = 80
httpPrefix = 'https'
federationList = []
baseDir = currDir + '/.tests_followersofperson'
if os.path.isdir(baseDir):
shutil.rmtree(baseDir)
os.mkdir(baseDir)
2020-03-22 21:16:02 +00:00
os.chdir(baseDir)
2020-04-05 13:25:47 +00:00
createPerson(baseDir, nickname, domain, port,
2020-07-12 12:31:28 +00:00
httpPrefix, True, False, password)
2020-04-05 13:25:47 +00:00
createPerson(baseDir, 'maxboardroom', domain, port,
2020-07-12 12:31:28 +00:00
httpPrefix, True, False, password)
2020-04-05 13:25:47 +00:00
createPerson(baseDir, 'ultrapancake', domain, port,
2020-07-12 12:31:28 +00:00
httpPrefix, True, False, password)
2020-04-05 13:25:47 +00:00
createPerson(baseDir, 'drokk', domain, port,
2020-07-12 12:31:28 +00:00
httpPrefix, True, False, password)
2020-04-05 13:25:47 +00:00
createPerson(baseDir, 'sausagedog', domain, port,
2020-07-12 12:31:28 +00:00
httpPrefix, True, False, password)
2020-04-05 13:25:47 +00:00
clearFollows(baseDir, nickname, domain)
followPerson(baseDir, nickname, domain, 'maxboardroom', domain,
federationList, False)
followPerson(baseDir, 'drokk', domain, 'ultrapancake', domain,
federationList, False)
# deliberate duplication
2020-04-05 13:25:47 +00:00
followPerson(baseDir, 'drokk', domain, 'ultrapancake', domain,
federationList, False)
followPerson(baseDir, 'sausagedog', domain, 'ultrapancake', domain,
federationList, False)
followPerson(baseDir, nickname, domain, 'ultrapancake', domain,
federationList, False)
followPerson(baseDir, nickname, domain, 'someother', 'randodomain.net',
federationList, False)
followList = getFollowersOfPerson(baseDir, 'ultrapancake', domain)
assert len(followList) == 3
assert 'mxpop@' + domain in followList
assert 'drokk@' + domain in followList
assert 'sausagedog@' + domain in followList
os.chdir(currDir)
shutil.rmtree(baseDir)
2020-04-05 13:25:47 +00:00
def testNoOfFollowersOnDomain():
print('testNoOfFollowersOnDomain')
2020-04-05 13:25:47 +00:00
currDir = os.getcwd()
nickname = 'mxpop'
domain = 'diva.domain'
otherdomain = 'soup.dragon'
password = 'birb'
port = 80
httpPrefix = 'https'
federationList = []
baseDir = currDir + '/.tests_nooffollowersOndomain'
if os.path.isdir(baseDir):
shutil.rmtree(baseDir)
os.mkdir(baseDir)
2020-03-22 21:16:02 +00:00
os.chdir(baseDir)
2020-07-12 12:31:28 +00:00
createPerson(baseDir, nickname, domain, port, httpPrefix, True,
False, password)
2020-04-05 13:25:47 +00:00
createPerson(baseDir, 'maxboardroom', otherdomain, port,
2020-07-12 12:31:28 +00:00
httpPrefix, True, False, password)
2020-04-05 13:25:47 +00:00
createPerson(baseDir, 'ultrapancake', otherdomain, port,
2020-07-12 12:31:28 +00:00
httpPrefix, True, False, password)
2020-04-05 13:25:47 +00:00
createPerson(baseDir, 'drokk', otherdomain, port,
2020-07-12 12:31:28 +00:00
httpPrefix, True, False, password)
2020-04-05 13:25:47 +00:00
createPerson(baseDir, 'sausagedog', otherdomain, port,
2020-07-12 12:31:28 +00:00
httpPrefix, True, False, password)
2020-04-05 13:25:47 +00:00
followPerson(baseDir, 'drokk', otherdomain, nickname, domain,
federationList, False)
followPerson(baseDir, 'sausagedog', otherdomain, nickname, domain,
federationList, False)
followPerson(baseDir, 'maxboardroom', otherdomain, nickname, domain,
federationList, False)
followerOfPerson(baseDir, nickname, domain,
'cucumber', 'sandwiches.party',
federationList, False)
followerOfPerson(baseDir, nickname, domain,
'captainsensible', 'damned.zone',
federationList, False)
followerOfPerson(baseDir, nickname, domain, 'pilchard', 'zombies.attack',
federationList, False)
followerOfPerson(baseDir, nickname, domain, 'drokk', otherdomain,
federationList, False)
followerOfPerson(baseDir, nickname, domain, 'sausagedog', otherdomain,
federationList, False)
followerOfPerson(baseDir, nickname, domain, 'maxboardroom', otherdomain,
federationList, False)
followersOnOtherDomain = \
noOfFollowersOnDomain(baseDir, nickname + '@' + domain, otherdomain)
assert followersOnOtherDomain == 3
2020-12-22 13:57:24 +00:00
unfollowerOfAccount(baseDir, nickname, domain, 'sausagedog', otherdomain)
2020-04-05 13:25:47 +00:00
followersOnOtherDomain = \
noOfFollowersOnDomain(baseDir, nickname + '@' + domain, otherdomain)
assert followersOnOtherDomain == 2
2020-03-22 21:16:02 +00:00
os.chdir(currDir)
shutil.rmtree(baseDir)
2020-04-05 13:25:47 +00:00
def testGroupFollowers():
print('testGroupFollowers')
2020-04-05 13:25:47 +00:00
currDir = os.getcwd()
nickname = 'test735'
domain = 'mydomain.com'
password = 'somepass'
port = 80
httpPrefix = 'https'
federationList = []
baseDir = currDir + '/.tests_testgroupfollowers'
if os.path.isdir(baseDir):
shutil.rmtree(baseDir)
os.mkdir(baseDir)
2020-03-22 21:16:02 +00:00
os.chdir(baseDir)
2020-07-12 12:31:28 +00:00
createPerson(baseDir, nickname, domain, port, httpPrefix, True,
False, password)
2020-04-05 13:25:47 +00:00
clearFollowers(baseDir, nickname, domain)
followerOfPerson(baseDir, nickname, domain, 'badger', 'wild.domain',
federationList, False)
followerOfPerson(baseDir, nickname, domain, 'squirrel', 'wild.domain',
federationList, False)
followerOfPerson(baseDir, nickname, domain, 'rodent', 'wild.domain',
federationList, False)
followerOfPerson(baseDir, nickname, domain, 'utterly', 'clutterly.domain',
federationList, False)
followerOfPerson(baseDir, nickname, domain, 'zonked', 'zzz.domain',
federationList, False)
followerOfPerson(baseDir, nickname, domain, 'nap', 'zzz.domain',
federationList, False)
grouped = groupFollowersByDomain(baseDir, nickname, domain)
assert len(grouped.items()) == 3
assert grouped.get('zzz.domain')
assert grouped.get('clutterly.domain')
assert grouped.get('wild.domain')
2020-04-05 13:25:47 +00:00
assert len(grouped['zzz.domain']) == 2
assert len(grouped['wild.domain']) == 3
assert len(grouped['clutterly.domain']) == 1
2020-03-22 21:16:02 +00:00
os.chdir(currDir)
shutil.rmtree(baseDir)
2020-03-22 21:16:02 +00:00
2019-07-03 09:24:55 +00:00
def testFollows():
2019-07-03 10:04:23 +00:00
print('testFollows')
2020-04-05 13:25:47 +00:00
currDir = os.getcwd()
nickname = 'test529'
domain = 'testdomain.com'
password = 'mypass'
port = 80
httpPrefix = 'https'
federationList = ['wild.com', 'mesh.com']
baseDir = currDir + '/.tests_testfollows'
2019-07-03 09:24:55 +00:00
if os.path.isdir(baseDir):
shutil.rmtree(baseDir)
os.mkdir(baseDir)
2020-03-22 21:16:02 +00:00
os.chdir(baseDir)
2020-07-12 12:31:28 +00:00
createPerson(baseDir, nickname, domain, port, httpPrefix, True,
False, password)
2020-04-05 13:25:47 +00:00
clearFollows(baseDir, nickname, domain)
followPerson(baseDir, nickname, domain, 'badger', 'wild.com',
federationList, False)
followPerson(baseDir, nickname, domain, 'squirrel', 'secret.com',
federationList, False)
followPerson(baseDir, nickname, domain, 'rodent', 'drainpipe.com',
federationList, False)
followPerson(baseDir, nickname, domain, 'batman', 'mesh.com',
federationList, False)
followPerson(baseDir, nickname, domain, 'giraffe', 'trees.com',
federationList, False)
f = open(baseDir + '/accounts/' + nickname + '@' + domain +
'/following.txt', "r")
domainFound = False
2019-07-03 09:24:55 +00:00
for followingDomain in f:
2020-05-22 11:32:38 +00:00
testDomain = followingDomain.split('@')[1]
testDomain = testDomain.replace('\n', '').replace('\r', '')
2020-04-05 13:25:47 +00:00
if testDomain == 'mesh.com':
domainFound = True
2019-07-03 09:24:55 +00:00
if testDomain not in federationList:
print(testDomain)
assert(False)
2019-07-03 09:33:28 +00:00
assert(domainFound)
2020-12-22 13:57:24 +00:00
unfollowAccount(baseDir, nickname, domain, 'batman', 'mesh.com')
2019-07-03 09:33:28 +00:00
2020-04-05 13:25:47 +00:00
domainFound = False
2019-07-03 09:33:28 +00:00
for followingDomain in f:
2020-05-22 11:32:38 +00:00
testDomain = followingDomain.split('@')[1]
testDomain = testDomain.replace('\n', '').replace('\r', '')
2020-04-05 13:25:47 +00:00
if testDomain == 'mesh.com':
domainFound = True
assert(domainFound is False)
clearFollowers(baseDir, nickname, domain)
followerOfPerson(baseDir, nickname, domain, 'badger', 'wild.com',
federationList, False)
followerOfPerson(baseDir, nickname, domain, 'squirrel', 'secret.com',
federationList, False)
followerOfPerson(baseDir, nickname, domain, 'rodent', 'drainpipe.com',
federationList, False)
followerOfPerson(baseDir, nickname, domain, 'batman', 'mesh.com',
federationList, False)
followerOfPerson(baseDir, nickname, domain, 'giraffe', 'trees.com',
federationList, False)
f = open(baseDir + '/accounts/' + nickname + '@' + domain +
'/followers.txt', "r")
2019-07-03 09:24:55 +00:00
for followerDomain in f:
2020-05-22 11:32:38 +00:00
testDomain = followerDomain.split('@')[1]
testDomain = testDomain.replace('\n', '').replace('\r', '')
2019-07-03 09:24:55 +00:00
if testDomain not in federationList:
print(testDomain)
assert(False)
os.chdir(currDir)
shutil.rmtree(baseDir)
2019-07-03 10:04:23 +00:00
2020-04-05 13:25:47 +00:00
2019-07-03 10:04:23 +00:00
def testCreatePerson():
print('testCreatePerson')
2020-04-05 13:25:47 +00:00
currDir = os.getcwd()
nickname = 'test382'
domain = 'badgerdomain.com'
password = 'mypass'
port = 80
httpPrefix = 'https'
clientToServer = False
baseDir = currDir + '/.tests_createperson'
2019-07-03 10:04:23 +00:00
if os.path.isdir(baseDir):
shutil.rmtree(baseDir)
os.mkdir(baseDir)
os.chdir(baseDir)
2020-03-22 21:16:02 +00:00
2020-04-05 13:25:47 +00:00
privateKeyPem, publicKeyPem, person, wfEndpoint = \
createPerson(baseDir, nickname, domain, port,
2020-07-12 12:31:28 +00:00
httpPrefix, True, False, password)
2020-04-05 13:25:47 +00:00
assert os.path.isfile(baseDir + '/accounts/passwords')
deleteAllPosts(baseDir, nickname, domain, 'inbox')
deleteAllPosts(baseDir, nickname, domain, 'outbox')
setDisplayNickname(baseDir, nickname, domain, 'badger')
setBio(baseDir, nickname, domain, 'Randomly roaming in your backyard')
archivePostsForPerson(nickname, domain, baseDir, 'inbox', None, {}, 4)
archivePostsForPerson(nickname, domain, baseDir, 'outbox', None, {}, 4)
2020-04-05 13:25:47 +00:00
createPublicPost(baseDir, nickname, domain, port, httpPrefix,
"G'day world!", False, True, clientToServer,
True, None, None, None, None,
2020-04-05 13:25:47 +00:00
'Not suitable for Vogons')
2019-07-03 10:04:23 +00:00
os.chdir(currDir)
shutil.rmtree(baseDir)
2020-04-05 13:25:47 +00:00
2019-07-18 16:21:26 +00:00
def testDelegateRoles():
print('testDelegateRoles')
2020-04-05 13:25:47 +00:00
currDir = os.getcwd()
nickname = 'test382'
nicknameDelegated = 'test383'
domain = 'badgerdomain.com'
password = 'mypass'
port = 80
httpPrefix = 'https'
baseDir = currDir + '/.tests_delegaterole'
2019-07-18 16:21:26 +00:00
if os.path.isdir(baseDir):
shutil.rmtree(baseDir)
os.mkdir(baseDir)
os.chdir(baseDir)
2020-03-22 21:16:02 +00:00
2020-04-05 13:25:47 +00:00
privateKeyPem, publicKeyPem, person, wfEndpoint = \
createPerson(baseDir, nickname, domain, port,
2020-07-12 12:31:28 +00:00
httpPrefix, True, False, password)
2020-04-05 13:25:47 +00:00
privateKeyPem, publicKeyPem, person, wfEndpoint = \
createPerson(baseDir, nicknameDelegated, domain, port,
2020-07-12 12:31:28 +00:00
httpPrefix, True, False, 'insecure')
2020-04-05 13:25:47 +00:00
httpPrefix = 'http'
project = 'artechoke'
role = 'delegator'
actorDelegated = \
httpPrefix + '://' + domain + '/users/' + nicknameDelegated
newRoleJson = {
2019-07-18 16:21:26 +00:00
'type': 'Delegate',
2020-04-05 13:25:47 +00:00
'actor': httpPrefix + '://' + domain + '/users/' + nickname,
2019-07-18 16:21:26 +00:00
'object': {
'type': 'Role',
2020-04-05 13:25:47 +00:00
'actor': actorDelegated,
'object': project + ';' + role,
2019-07-18 16:21:26 +00:00
'to': [],
2020-03-22 21:16:02 +00:00
'cc': []
2019-07-18 16:21:26 +00:00
},
'to': [],
'cc': []
}
2020-04-05 13:25:47 +00:00
assert outboxDelegate(baseDir, nickname, newRoleJson, False)
2019-07-18 16:21:26 +00:00
# second time delegation has already happened so should return false
2020-04-05 13:25:47 +00:00
assert outboxDelegate(baseDir, nickname, newRoleJson, False) is False
2019-07-18 16:21:26 +00:00
2020-04-05 13:25:47 +00:00
assert '"delegator"' in open(baseDir + '/accounts/' + nickname +
'@' + domain + '.json').read()
assert '"delegator"' in open(baseDir + '/accounts/' + nicknameDelegated +
'@' + domain + '.json').read()
2020-03-22 21:16:02 +00:00
2020-04-05 13:25:47 +00:00
newRoleJson = {
2019-07-18 16:21:26 +00:00
'type': 'Delegate',
2020-04-05 13:25:47 +00:00
'actor': httpPrefix + '://' + domain + '/users/' + nicknameDelegated,
2019-07-18 16:21:26 +00:00
'object': {
'type': 'Role',
2020-04-05 13:25:47 +00:00
'actor': httpPrefix + '://' + domain + '/users/' + nickname,
2019-07-18 16:21:26 +00:00
'object': 'otherproject;otherrole',
'to': [],
2020-03-22 21:16:02 +00:00
'cc': []
2019-07-18 16:21:26 +00:00
},
'to': [],
'cc': []
}
# non-delegators cannot assign roles
2020-04-05 13:25:47 +00:00
assert outboxDelegate(baseDir, nicknameDelegated,
newRoleJson, False) is False
assert '"otherrole"' not in open(baseDir + '/accounts/' +
nickname + '@' + domain + '.json').read()
2019-07-18 16:21:26 +00:00
os.chdir(currDir)
shutil.rmtree(baseDir)
2020-04-05 13:25:47 +00:00
2019-07-03 18:24:44 +00:00
def testAuthentication():
print('testAuthentication')
2020-04-05 13:25:47 +00:00
currDir = os.getcwd()
nickname = 'test8743'
password = 'SuperSecretPassword12345'
2019-07-03 18:24:44 +00:00
2020-04-05 13:25:47 +00:00
baseDir = currDir + '/.tests_authentication'
2019-07-03 18:24:44 +00:00
if os.path.isdir(baseDir):
shutil.rmtree(baseDir)
os.mkdir(baseDir)
os.chdir(baseDir)
2020-04-05 13:25:47 +00:00
assert storeBasicCredentials(baseDir, 'othernick', 'otherpass')
assert storeBasicCredentials(baseDir, 'bad:nick', 'otherpass') is False
assert storeBasicCredentials(baseDir, 'badnick', 'otherpa:ss') is False
assert storeBasicCredentials(baseDir, nickname, password)
2019-07-03 18:24:44 +00:00
2020-04-05 13:25:47 +00:00
authHeader = createBasicAuthHeader(nickname, password)
assert authorizeBasic(baseDir, '/users/' + nickname + '/inbox',
authHeader, False)
assert authorizeBasic(baseDir, '/users/' + nickname,
authHeader, False) is False
assert authorizeBasic(baseDir, '/users/othernick/inbox',
authHeader, False) is False
2019-07-03 18:24:44 +00:00
2020-04-05 13:25:47 +00:00
authHeader = createBasicAuthHeader(nickname, password + '1')
assert authorizeBasic(baseDir, '/users/' + nickname + '/inbox',
authHeader, False) is False
2019-07-03 18:24:44 +00:00
2020-04-05 13:25:47 +00:00
password = 'someOtherPassword'
assert storeBasicCredentials(baseDir, nickname, password)
2019-07-03 19:13:23 +00:00
2020-04-05 13:25:47 +00:00
authHeader = createBasicAuthHeader(nickname, password)
assert authorizeBasic(baseDir, '/users/' + nickname + '/inbox',
authHeader, False)
2019-07-03 19:13:23 +00:00
2019-07-03 18:24:44 +00:00
os.chdir(currDir)
shutil.rmtree(baseDir)
2019-07-16 10:19:04 +00:00
2020-04-05 13:25:47 +00:00
2019-07-16 10:19:04 +00:00
def testClientToServer():
print('Testing sending a post via c2s')
global testServerAliceRunning
global testServerBobRunning
2020-04-05 13:25:47 +00:00
testServerAliceRunning = False
testServerBobRunning = False
2019-07-16 10:19:04 +00:00
2020-04-05 13:25:47 +00:00
httpPrefix = 'http'
2020-06-09 11:03:59 +00:00
proxyType = None
2020-04-05 13:25:47 +00:00
federationList = []
2019-07-16 10:19:04 +00:00
2020-04-05 13:25:47 +00:00
baseDir = os.getcwd()
if os.path.isdir(baseDir + '/.tests'):
shutil.rmtree(baseDir + '/.tests')
os.mkdir(baseDir + '/.tests')
2019-07-16 10:19:04 +00:00
# create the servers
2020-04-05 13:25:47 +00:00
aliceDir = baseDir + '/.tests/alice'
aliceDomain = '127.0.0.42'
alicePort = 61935
aliceSendThreads = []
aliceAddress = aliceDomain + ':' + str(alicePort)
bobDir = baseDir + '/.tests/bob'
bobDomain = '127.0.0.64'
bobPort = 61936
bobSendThreads = []
bobAddress = bobDomain + ':' + str(bobPort)
2020-02-19 12:27:21 +00:00
global thrAlice
if thrAlice:
2020-12-18 15:29:12 +00:00
while thrAlice.is_alive():
2020-02-19 12:27:21 +00:00
thrAlice.stop()
time.sleep(1)
thrAlice.kill()
2020-04-05 13:25:47 +00:00
thrAlice = \
threadWithTrace(target=createServerAlice,
args=(aliceDir, aliceDomain, alicePort, bobAddress,
federationList, False, False,
2020-09-27 19:27:24 +00:00
aliceSendThreads),
2020-04-05 13:25:47 +00:00
daemon=True)
2020-03-22 21:16:02 +00:00
2020-02-19 12:27:21 +00:00
global thrBob
if thrBob:
2020-12-18 15:29:12 +00:00
while thrBob.is_alive():
2020-02-19 12:27:21 +00:00
thrBob.stop()
time.sleep(1)
thrBob.kill()
2020-04-05 13:25:47 +00:00
thrBob = \
threadWithTrace(target=createServerBob,
args=(bobDir, bobDomain, bobPort, aliceAddress,
federationList, False, False,
2020-09-27 19:27:24 +00:00
bobSendThreads),
2020-04-05 13:25:47 +00:00
daemon=True)
2019-07-16 10:19:04 +00:00
thrAlice.start()
thrBob.start()
2020-12-18 15:29:12 +00:00
assert thrAlice.is_alive() is True
assert thrBob.is_alive() is True
2019-07-16 10:19:04 +00:00
# wait for both servers to be running
2020-04-05 13:25:47 +00:00
ctr = 0
2019-07-16 10:19:04 +00:00
while not (testServerAliceRunning and testServerBobRunning):
time.sleep(1)
2020-04-05 13:25:47 +00:00
ctr += 1
if ctr > 60:
2019-07-16 10:19:04 +00:00
break
2020-04-05 13:25:47 +00:00
print('Alice online: ' + str(testServerAliceRunning))
print('Bob online: ' + str(testServerBobRunning))
2019-07-16 10:19:04 +00:00
time.sleep(1)
2020-03-22 21:16:02 +00:00
2019-07-16 10:19:04 +00:00
print('\n\n*******************************************************')
print('Alice sends to Bob via c2s')
2020-06-09 11:03:59 +00:00
sessionAlice = createSession(proxyType)
2020-04-05 13:25:47 +00:00
followersOnly = False
attachedImageFilename = baseDir+'/img/logo.png'
mediaType = getAttachmentMediaType(attachedImageFilename)
attachedImageDescription = 'Logo'
isArticle = False
cachedWebfingers = {}
personCache = {}
password = 'alicepass'
outboxPath = aliceDir + '/accounts/alice@' + aliceDomain + '/outbox'
inboxPath = bobDir + '/accounts/bob@' + bobDomain + '/inbox'
assert len([name for name in os.listdir(outboxPath)
if os.path.isfile(os.path.join(outboxPath, name))]) == 0
assert len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath, name))]) == 0
sendResult = \
sendPostViaServer(__version__,
aliceDir, sessionAlice, 'alice', password,
aliceDomain, alicePort,
'bob', bobDomain, bobPort, None,
httpPrefix, 'Sent from my ActivityPub client',
2020-08-21 17:40:50 +00:00
followersOnly, True,
2020-04-05 13:25:47 +00:00
attachedImageFilename, mediaType,
attachedImageDescription,
2020-04-05 13:25:47 +00:00
cachedWebfingers, personCache, isArticle,
True, None, None, None)
print('sendResult: ' + str(sendResult))
2019-07-16 10:19:04 +00:00
for i in range(30):
if os.path.isdir(outboxPath):
2020-04-05 13:25:47 +00:00
if len([name for name in os.listdir(outboxPath)
if os.path.isfile(os.path.join(outboxPath, name))]) == 1:
2019-07-16 10:19:04 +00:00
break
time.sleep(1)
2019-07-16 11:33:40 +00:00
2020-04-05 13:25:47 +00:00
assert len([name for name in os.listdir(outboxPath)
if os.path.isfile(os.path.join(outboxPath, name))]) == 1
2019-07-16 11:33:40 +00:00
print(">>> c2s post arrived in Alice's outbox")
2020-03-22 21:16:02 +00:00
2019-07-16 11:33:40 +00:00
for i in range(30):
if os.path.isdir(inboxPath):
2020-04-05 13:25:47 +00:00
if len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath, name))]) == 1:
2019-07-16 11:33:40 +00:00
break
time.sleep(1)
2020-04-05 13:25:47 +00:00
assert len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath, name))]) == 1
2019-07-16 11:33:40 +00:00
print(">>> s2s post arrived in Bob's inbox")
print("c2s send success")
2019-07-16 19:07:45 +00:00
print('\n\nGetting message id for the post')
2020-04-05 13:25:47 +00:00
statusNumber = 0
outboxPostFilename = None
outboxPostId = None
2019-07-16 19:07:45 +00:00
for name in os.listdir(outboxPath):
if '#statuses#' in name:
2020-04-05 13:25:47 +00:00
statusNumber = name.split('#statuses#')[1].replace('.json', '')
statusNumber = int(statusNumber.replace('#activity', ''))
outboxPostFilename = outboxPath + '/' + name
postJsonObject = loadJson(outboxPostFilename, 0)
if postJsonObject:
2020-08-23 11:13:35 +00:00
outboxPostId = removeIdEnding(postJsonObject['id'])
2019-07-16 19:07:45 +00:00
assert outboxPostId
2020-04-05 13:25:47 +00:00
print('message id obtained: ' + outboxPostId)
assert validInbox(bobDir, 'bob', bobDomain)
assert validInboxFilenames(bobDir, 'bob', bobDomain,
aliceDomain, alicePort)
2019-07-16 21:38:06 +00:00
print('\n\nAlice follows Bob')
2020-04-05 13:25:47 +00:00
sendFollowRequestViaServer(aliceDir, sessionAlice,
'alice', password,
aliceDomain, alicePort,
'bob', bobDomain, bobPort,
httpPrefix,
cachedWebfingers, personCache,
True, __version__)
2020-11-23 15:07:55 +00:00
alicePetnamesFilename = aliceDir + '/accounts/' + \
'alice@' + aliceDomain + '/petnames.txt'
2020-04-05 13:25:47 +00:00
aliceFollowingFilename = \
aliceDir + '/accounts/alice@' + aliceDomain + '/following.txt'
bobFollowersFilename = \
bobDir + '/accounts/bob@' + bobDomain + '/followers.txt'
2020-03-02 21:28:22 +00:00
for t in range(10):
if os.path.isfile(bobFollowersFilename):
2020-04-05 13:25:47 +00:00
if 'alice@' + aliceDomain + ':' + str(alicePort) in \
open(bobFollowersFilename).read():
2020-11-23 15:07:55 +00:00
if os.path.isfile(aliceFollowingFilename) and \
os.path.isfile(alicePetnamesFilename):
2020-04-05 13:25:47 +00:00
if 'bob@' + bobDomain + ':' + str(bobPort) in \
open(aliceFollowingFilename).read():
2019-07-17 11:24:11 +00:00
break
2019-07-16 21:38:06 +00:00
time.sleep(1)
2020-03-02 21:28:22 +00:00
assert os.path.isfile(bobFollowersFilename)
assert os.path.isfile(aliceFollowingFilename)
2020-11-23 15:07:55 +00:00
assert os.path.isfile(alicePetnamesFilename)
assert 'bob bob@' + bobDomain in \
open(alicePetnamesFilename).read()
2020-04-05 13:25:47 +00:00
print('alice@' + aliceDomain + ':' + str(alicePort) + ' in ' +
bobFollowersFilename)
assert 'alice@' + aliceDomain + ':' + str(alicePort) in \
open(bobFollowersFilename).read()
print('bob@' + bobDomain + ':' + str(bobPort) + ' in ' +
aliceFollowingFilename)
assert 'bob@' + bobDomain + ':' + str(bobPort) in \
open(aliceFollowingFilename).read()
assert validInbox(bobDir, 'bob', bobDomain)
assert validInboxFilenames(bobDir, 'bob', bobDomain,
aliceDomain, alicePort)
2019-07-17 17:16:48 +00:00
print('\n\nBob follows Alice')
2020-04-05 13:25:47 +00:00
sendFollowRequestViaServer(aliceDir, sessionAlice,
'bob', 'bobpass',
bobDomain, bobPort,
'alice', aliceDomain, alicePort,
httpPrefix,
cachedWebfingers, personCache,
True, __version__)
2019-07-17 17:16:48 +00:00
for t in range(10):
2020-04-05 13:25:47 +00:00
if os.path.isfile(aliceDir + '/accounts/alice@' + aliceDomain +
'/followers.txt'):
if 'bob@' + bobDomain + ':' + str(bobPort) in \
open(aliceDir + '/accounts/alice@' + aliceDomain +
'/followers.txt').read():
if os.path.isfile(bobDir + '/accounts/bob@' + bobDomain +
'/following.txt'):
2020-07-03 21:56:38 +00:00
aliceHandleStr = \
'alice@' + aliceDomain + ':' + str(alicePort)
if aliceHandleStr in \
2020-04-05 13:25:47 +00:00
open(bobDir + '/accounts/bob@' + bobDomain +
'/following.txt').read():
2020-07-03 21:56:38 +00:00
if os.path.isfile(bobDir + '/accounts/bob@' +
bobDomain +
'/followingCalendar.txt'):
if aliceHandleStr in \
open(bobDir + '/accounts/bob@' + bobDomain +
'/followingCalendar.txt').read():
break
2019-07-17 17:16:48 +00:00
time.sleep(1)
2020-04-05 13:25:47 +00:00
assert os.path.isfile(aliceDir + '/accounts/alice@' + aliceDomain +
'/followers.txt')
assert os.path.isfile(bobDir + '/accounts/bob@' + bobDomain +
'/following.txt')
assert 'bob@' + bobDomain + ':' + str(bobPort) in \
open(aliceDir + '/accounts/alice@' + aliceDomain +
'/followers.txt').read()
assert 'alice@' + aliceDomain + ':' + str(alicePort) in \
open(bobDir + '/accounts/bob@' + bobDomain + '/following.txt').read()
print('\n\nBob likes the post')
2020-06-09 11:03:59 +00:00
sessionBob = createSession(proxyType)
2020-04-05 13:25:47 +00:00
password = 'bobpass'
outboxPath = bobDir + '/accounts/bob@' + bobDomain + '/outbox'
inboxPath = aliceDir + '/accounts/alice@' + aliceDomain + '/inbox'
print(str(len([name for name in os.listdir(outboxPath)
if os.path.isfile(os.path.join(outboxPath, name))])))
assert len([name for name in os.listdir(outboxPath)
if os.path.isfile(os.path.join(outboxPath, name))]) == 1
print(str(len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath, name))])))
assert len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath, name))]) == 1
sendLikeViaServer(bobDir, sessionBob,
'bob', 'bobpass',
bobDomain, bobPort,
httpPrefix, outboxPostId,
cachedWebfingers, personCache,
True, __version__)
for i in range(20):
2020-03-22 21:16:02 +00:00
if os.path.isdir(outboxPath) and os.path.isdir(inboxPath):
2020-04-05 13:25:47 +00:00
if len([name for name in os.listdir(outboxPath)
if os.path.isfile(os.path.join(outboxPath, name))]) == 2:
test = len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath, name))])
if test == 1:
break
time.sleep(1)
2020-04-05 13:25:47 +00:00
assert len([name for name in os.listdir(outboxPath)
if os.path.isfile(os.path.join(outboxPath, name))]) == 2
assert len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath, name))]) == 1
print('Post liked')
2020-03-22 21:16:02 +00:00
print('\n\nBob repeats the post')
2020-04-05 13:25:47 +00:00
print(str(len([name for name in os.listdir(outboxPath)
if os.path.isfile(os.path.join(outboxPath, name))])))
assert len([name for name in os.listdir(outboxPath)
if os.path.isfile(os.path.join(outboxPath, name))]) == 2
print(str(len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath, name))])))
assert len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath, name))]) == 1
sendAnnounceViaServer(bobDir, sessionBob, 'bob', password,
bobDomain, bobPort,
httpPrefix, outboxPostId,
cachedWebfingers,
personCache, True, __version__)
2019-07-16 22:57:45 +00:00
for i in range(20):
2020-03-22 21:16:02 +00:00
if os.path.isdir(outboxPath) and os.path.isdir(inboxPath):
2020-04-05 13:25:47 +00:00
if len([name for name in os.listdir(outboxPath)
if os.path.isfile(os.path.join(outboxPath, name))]) == 3:
if len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath,
name))]) == 2:
2019-07-16 22:57:45 +00:00
break
2019-07-16 19:07:45 +00:00
time.sleep(1)
2020-04-05 13:25:47 +00:00
assert len([name for name in os.listdir(outboxPath)
if os.path.isfile(os.path.join(outboxPath, name))]) == 3
assert len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath, name))]) == 2
2019-07-16 19:07:45 +00:00
print('Post repeated')
2019-07-17 11:54:13 +00:00
2020-04-05 13:25:47 +00:00
inboxPath = bobDir + '/accounts/bob@' + bobDomain + '/inbox'
outboxPath = aliceDir + '/accounts/alice@' + aliceDomain + '/outbox'
postsBefore = \
len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath, name))])
print('\n\nAlice deletes her post: ' + outboxPostId + ' ' +
str(postsBefore))
password = 'alicepass'
sendDeleteViaServer(aliceDir, sessionAlice, 'alice', password,
aliceDomain, alicePort,
httpPrefix, outboxPostId,
cachedWebfingers, personCache,
True, __version__)
2019-07-17 17:16:48 +00:00
for i in range(30):
if os.path.isdir(inboxPath):
2020-04-05 13:25:47 +00:00
test = len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath, name))])
if test == postsBefore-1:
2019-07-17 17:16:48 +00:00
break
time.sleep(1)
2020-04-05 13:25:47 +00:00
test = len([name for name in os.listdir(inboxPath)
if os.path.isfile(os.path.join(inboxPath, name))])
assert test == postsBefore - 1
2019-07-17 17:16:48 +00:00
print(">>> post deleted from Alice's outbox and Bob's inbox")
2020-04-05 13:25:47 +00:00
assert validInbox(bobDir, 'bob', bobDomain)
assert validInboxFilenames(bobDir, 'bob', bobDomain,
aliceDomain, alicePort)
2020-03-22 21:16:02 +00:00
2019-07-17 11:54:13 +00:00
print('\n\nAlice unfollows Bob')
2020-04-05 13:25:47 +00:00
password = 'alicepass'
sendUnfollowRequestViaServer(baseDir, sessionAlice,
'alice', password,
aliceDomain, alicePort,
'bob', bobDomain, bobPort,
httpPrefix,
cachedWebfingers, personCache,
True, __version__)
2019-07-17 11:54:13 +00:00
for t in range(10):
2020-04-05 13:25:47 +00:00
if 'alice@' + aliceDomain + ':' + str(alicePort) not in \
open(bobFollowersFilename).read():
if 'bob@' + bobDomain + ':' + str(bobPort) not in \
open(aliceFollowingFilename).read():
2019-07-17 11:54:13 +00:00
break
time.sleep(1)
2020-03-02 21:28:22 +00:00
assert os.path.isfile(bobFollowersFilename)
assert os.path.isfile(aliceFollowingFilename)
2020-04-05 13:25:47 +00:00
assert 'alice@' + aliceDomain + ':' + str(alicePort) \
not in open(bobFollowersFilename).read()
assert 'bob@' + bobDomain + ':' + str(bobPort) \
not in open(aliceFollowingFilename).read()
assert validInbox(bobDir, 'bob', bobDomain)
assert validInboxFilenames(bobDir, 'bob', bobDomain,
aliceDomain, alicePort)
assert validInbox(aliceDir, 'alice', aliceDomain)
assert validInboxFilenames(aliceDir, 'alice', aliceDomain,
bobDomain, bobPort)
2019-07-17 11:54:13 +00:00
2019-07-16 11:33:40 +00:00
# stop the servers
thrAlice.kill()
thrAlice.join()
2020-12-18 15:29:12 +00:00
assert thrAlice.is_alive() is False
2019-07-16 11:33:40 +00:00
thrBob.kill()
thrBob.join()
2020-12-18 15:29:12 +00:00
assert thrBob.is_alive() is False
2019-07-16 11:33:40 +00:00
os.chdir(baseDir)
2020-04-05 13:25:47 +00:00
# shutil.rmtree(aliceDir)
# shutil.rmtree(bobDir)
2019-07-16 10:19:04 +00:00
2019-08-21 16:35:46 +00:00
def testActorParsing():
print('testActorParsing')
2020-04-05 13:25:47 +00:00
actor = 'https://mydomain:72/users/mynick'
domain, port = getDomainFromActor(actor)
assert domain == 'mydomain'
assert port == 72
nickname = getNicknameFromActor(actor)
assert nickname == 'mynick'
2020-08-13 16:41:02 +00:00
actor = 'https://element/accounts/badger'
domain, port = getDomainFromActor(actor)
assert domain == 'element'
nickname = getNicknameFromActor(actor)
assert nickname == 'badger'
actor = 'egg@chicken.com'
domain, port = getDomainFromActor(actor)
assert domain == 'chicken.com'
nickname = getNicknameFromActor(actor)
assert nickname == 'egg'
actor = '@waffle@cardboard'
domain, port = getDomainFromActor(actor)
assert domain == 'cardboard'
nickname = getNicknameFromActor(actor)
assert nickname == 'waffle'
actor = 'https://astral/channel/sky'
domain, port = getDomainFromActor(actor)
assert domain == 'astral'
nickname = getNicknameFromActor(actor)
assert nickname == 'sky'
2020-04-05 13:25:47 +00:00
actor = 'https://randomain/users/rando'
domain, port = getDomainFromActor(actor)
assert domain == 'randomain'
nickname = getNicknameFromActor(actor)
assert nickname == 'rando'
actor = 'https://otherdomain:49/@othernick'
domain, port = getDomainFromActor(actor)
assert domain == 'otherdomain'
assert port == 49
nickname = getNicknameFromActor(actor)
assert nickname == 'othernick'
2019-08-21 16:35:46 +00:00
2019-09-01 08:55:05 +00:00
def testWebLinks():
2019-09-01 08:57:51 +00:00
print('testWebLinks')
2020-01-24 10:52:59 +00:00
2020-04-05 13:25:47 +00:00
exampleText = \
'<p><span class=\"h-card\"><a href=\"https://something/@orother' + \
'\" class=\"u-url mention\">@<span>foo</span></a></span> Some ' + \
'random text.</p><p>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' + \
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' + \
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' + \
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' + \
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' + \
'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</p>'
resultText = removeLongWords(exampleText, 40, [])
assert resultText == \
'<p><span class="h-card"><a href="https://something/@orother"' + \
' class="u-url mention">@<span>foo</span></a></span> ' + \
'Some random text.</p>'
exampleText = \
'This post has a web links https://somesite.net\n\nAnd some other text'
linkedText = addWebLinks(exampleText)
assert \
2020-12-13 11:31:16 +00:00
'<a href="https://somesite.net" rel="nofollow noopener noreferrer"' + \
2020-04-05 13:25:47 +00:00
' target="_blank"><span class="invisible">https://' + \
'</span><span class="ellipsis">somesite.net</span></a' in linkedText
exampleText = \
'This post has a very long web link\n\nhttp://' + \
'cbwebewuvfuftdiudbqd33dddbbyuef23fyug3bfhcyu2fct2' + \
'cuyqbcbucuwvckiwyfgewfvqejbchevbhwevuevwbqebqekve' + \
'qvuvjfkf.onion\n\nAnd some other text'
linkedText = addWebLinks(exampleText)
2019-10-01 10:36:51 +00:00
assert 'ellipsis' in linkedText
2020-01-24 10:52:59 +00:00
2020-04-05 13:25:47 +00:00
exampleText = \
'<p>1. HAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAH' + \
'AHAHAHHAHAHAHAHAHAHAHAHAHAHAHAHHAHAHAHAHAHAHAHAH</p>'
resultText = removeLongWords(exampleText, 40, [])
assert resultText == '<p>1. HAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAHA</p>'
exampleText = \
'<p>Tox address is 88AB9DED6F9FBEF43E105FB72060A2D89F9B93C74' + \
'4E8C45AB3C5E42C361C837155AFCFD9D448 </p>'
resultText = removeLongWords(exampleText, 40, [])
assert resultText == exampleText
2020-10-31 23:10:38 +00:00
exampleText = \
'some.incredibly.long.and.annoying.word.which.should.be.removed: ' + \
'The remaining text'
resultText = removeLongWords(exampleText, 40, [])
assert resultText == \
'some.incredibly.long.and.annoying.word.w\n' + \
'hich.should.be.removed: The remaining text'
2020-04-05 13:25:47 +00:00
exampleText = \
'<p>Tox address is 88AB9DED6F9FBEF43E105FB72060A2D89F9B93C74' + \
'4E8C45AB3C5E42C361C837155AFCFD9D448</p>'
resultText = removeLongWords(exampleText, 40, [])
assert resultText == \
'<p>Tox address is 88AB9DED6F9FBEF43E105FB72060A2D89F9B93C7\n' + \
'44E8C45AB3C5E42C361C837155AFCFD9D448</p>'
exampleText = \
'<p>ABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCA' + \
'BCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCAB' + \
'CABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABC' + \
'ABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCA' + \
'BCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCAB' + \
'CABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABC' + \
'ABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCA' + \
'BCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCAB' + \
'CABCABCABCABCABCABCABCABC</p>'
resultText = removeLongWords(exampleText, 40, [])
assert resultText == r'<p>ABCABCABCABCABCABCABCABCABCABCABCABCABCA<\p>'
exampleText = \
'"the nucleus of mutual-support institutions, habits, and customs ' + \
'remains alive with the millions; it keeps them together; and ' + \
'they prefer to cling to their customs, beliefs, and traditions ' + \
'rather than to accept the teachings of a war of each ' + \
'against all"\n\n--Peter Kropotkin'
testFnStr = addWebLinks(exampleText)
resultText = removeLongWords(testFnStr, 40, [])
2020-04-05 13:25:47 +00:00
assert resultText == exampleText
2020-03-29 10:48:31 +00:00
assert 'ellipsis' not in resultText
2020-03-29 09:59:54 +00:00
2020-05-12 09:34:58 +00:00
exampleText = \
'<p>' + \
'<<\\p>'
2020-05-12 09:34:58 +00:00
resultText = replaceContentDuplicates(exampleText)
assert resultText == \
'<p>' + \
''
2020-08-07 20:51:34 +00:00
exampleText = \
2020-08-11 17:18:22 +00:00
'<p>Test1 test2 #YetAnotherExcessivelyLongwindedAndBoringHashtag</p>'
testFnStr = addWebLinks(exampleText)
resultText = removeLongWords(testFnStr, 40, [])
2020-08-07 20:51:34 +00:00
assert(resultText ==
'<p>Test1 test2 '
'#YetAnotherExcessivelyLongwindedAndBorin\ngHashtag</p>')
2020-12-06 10:18:41 +00:00
exampleText = \
2020-12-06 14:47:06 +00:00
"<p>Don't remove a p2p link " + \
"rad:git:hwd1yrerc3mcgn8ga9rho3dqi4w33nep7kxmqezss4topyfgmexihp" + \
"33xcw</p>"
testFnStr = addWebLinks(exampleText)
resultText = removeLongWords(testFnStr, 40, [])
2020-12-06 10:18:41 +00:00
assert resultText == exampleText
2020-01-24 10:52:59 +00:00
2020-02-21 15:09:31 +00:00
def testAddEmoji():
print('testAddEmoji')
2020-04-05 13:25:47 +00:00
content = "Emoji :lemon: :strawberry: :banana:"
httpPrefix = 'http'
nickname = 'testuser'
domain = 'testdomain.net'
port = 3682
recipients = []
hashtags = {}
baseDir = os.getcwd()
baseDirOriginal = os.getcwd()
path = baseDir + '/.tests'
2019-09-29 18:48:34 +00:00
if not os.path.isdir(path):
os.mkdir(path)
2020-04-05 13:25:47 +00:00
path = baseDir + '/.tests/emoji'
2019-09-29 18:48:34 +00:00
if os.path.isdir(path):
shutil.rmtree(path)
2020-03-22 21:16:02 +00:00
os.mkdir(path)
2020-04-05 13:25:47 +00:00
baseDir = path
path = baseDir + '/emoji'
2019-09-29 18:48:34 +00:00
if os.path.isdir(path):
shutil.rmtree(path)
2020-03-22 21:16:02 +00:00
os.mkdir(path)
2020-04-05 13:25:47 +00:00
copytree(baseDirOriginal + '/emoji', baseDir + '/emoji')
2019-09-29 18:48:34 +00:00
os.chdir(baseDir)
2020-04-05 13:25:47 +00:00
privateKeyPem, publicKeyPem, person, wfEndpoint = \
createPerson(baseDir, nickname, domain, port,
2020-07-12 12:31:28 +00:00
httpPrefix, True, False, 'password')
2020-04-05 13:25:47 +00:00
contentModified = \
addHtmlTags(baseDir, httpPrefix,
nickname, domain, content,
recipients, hashtags, True)
2020-02-21 15:09:31 +00:00
assert ':lemon:' in contentModified
2020-02-21 09:53:36 +00:00
assert contentModified.startswith('<p>')
assert contentModified.endswith('</p>')
2020-04-05 13:25:47 +00:00
tags = []
for tagName, tag in hashtags.items():
2019-09-29 18:48:34 +00:00
tags.append(tag)
2020-04-05 13:25:47 +00:00
content = contentModified
contentModified = replaceEmojiFromTags(content, tags, 'content')
# print('contentModified: '+contentModified)
assert contentModified == '<p>Emoji 🍋 🍓 🍌</p>'
2019-09-29 18:48:34 +00:00
os.chdir(baseDirOriginal)
2020-04-05 13:25:47 +00:00
shutil.rmtree(baseDirOriginal + '/.tests')
2019-09-29 18:48:34 +00:00
2019-10-12 12:45:53 +00:00
def testGetStatusNumber():
print('testGetStatusNumber')
2020-04-05 13:25:47 +00:00
prevStatusNumber = None
for i in range(1, 20):
statusNumber, published = getStatusNumber()
2019-10-12 12:45:53 +00:00
if prevStatusNumber:
assert len(statusNumber) == 18
assert int(statusNumber) > prevStatusNumber
2020-04-05 13:25:47 +00:00
prevStatusNumber = int(statusNumber)
2019-10-12 12:45:53 +00:00
2020-10-11 12:41:15 +00:00
def testJsonString() -> None:
print('testJsonString')
2020-10-11 13:00:26 +00:00
filename = '.epicyon_tests_testJsonString.json'
2020-04-05 13:25:47 +00:00
messageStr = "Crème brûlée यह एक परीक्षण ह"
testJson = {
2019-11-09 12:13:39 +00:00
"content": messageStr
}
2020-04-05 13:25:47 +00:00
assert saveJson(testJson, filename)
receivedJson = loadJson(filename, 0)
2019-11-09 12:13:39 +00:00
assert receivedJson
2020-04-05 13:25:47 +00:00
assert receivedJson['content'] == messageStr
encodedStr = json.dumps(testJson, ensure_ascii=False)
assert messageStr in encodedStr
2020-10-11 13:00:26 +00:00
os.remove(filename)
2019-11-09 12:13:39 +00:00
2020-04-05 13:25:47 +00:00
2019-11-23 10:13:57 +00:00
def testSaveLoadJson():
print('testSaveLoadJson')
2020-04-05 13:25:47 +00:00
testJson = {
2019-11-23 10:13:57 +00:00
"param1": 3,
2019-11-23 10:20:30 +00:00
"param2": '"Crème brûlée यह एक परीक्षण ह"'
2019-11-23 10:13:57 +00:00
}
2020-10-11 13:03:08 +00:00
testFilename = '.epicyon_tests_testSaveLoadJson.json'
2019-11-23 10:13:57 +00:00
if os.path.isfile(testFilename):
os.remove(testFilename)
2020-04-05 13:25:47 +00:00
assert saveJson(testJson, testFilename)
2019-11-23 10:13:57 +00:00
assert os.path.isfile(testFilename)
2020-04-05 13:25:47 +00:00
testLoadJson = loadJson(testFilename)
2019-11-23 10:13:57 +00:00
assert(testLoadJson)
assert testLoadJson.get('param1')
assert testLoadJson.get('param2')
2020-04-05 13:25:47 +00:00
assert testLoadJson['param1'] == 3
assert testLoadJson['param2'] == '"Crème brûlée यह एक परीक्षण ह"'
2019-11-23 10:13:57 +00:00
os.remove(testFilename)
2019-11-23 13:04:11 +00:00
2020-04-05 13:25:47 +00:00
2019-11-23 13:04:11 +00:00
def testTheme():
print('testTheme')
2020-04-05 13:25:47 +00:00
css = 'somestring --background-value: 24px; --foreground-value: 24px;'
result = setCSSparam(css, 'background-value', '32px')
assert result == \
'somestring --background-value: 32px; --foreground-value: 24px;'
css = \
'somestring --background-value: 24px; --foreground-value: 24px; ' + \
'--background-value: 24px;'
result = setCSSparam(css, 'background-value', '32px')
assert result == \
'somestring --background-value: 32px; --foreground-value: 24px; ' + \
'--background-value: 32px;'
css = '--background-value: 24px; --foreground-value: 24px;'
result = setCSSparam(css, 'background-value', '32px')
assert result == '--background-value: 32px; --foreground-value: 24px;'
2019-11-23 13:04:11 +00:00
def testRecentPostsCache():
print('testRecentPostsCache')
2020-04-05 13:25:47 +00:00
recentPostsCache = {}
maxRecentPosts = 3
htmlStr = '<html></html>'
for i in range(5):
2020-04-05 13:25:47 +00:00
postJsonObject = {
"id": "https://somesite.whatever/users/someuser/statuses/"+str(i)
}
2020-04-05 13:25:47 +00:00
updateRecentPostsCache(recentPostsCache, maxRecentPosts,
postJsonObject, htmlStr)
assert len(recentPostsCache['index']) == maxRecentPosts
assert len(recentPostsCache['json'].items()) == maxRecentPosts
assert len(recentPostsCache['html'].items()) == maxRecentPosts
def testRemoveTextFormatting():
print('testRemoveTextFormatting')
testStr = '<p>Text without formatting</p>'
resultStr = removeTextFormatting(testStr)
assert(resultStr == testStr)
testStr = '<p>Text <i>with</i> <h3>formatting</h3></p>'
resultStr = removeTextFormatting(testStr)
assert(resultStr == '<p>Text with formatting</p>')
2020-06-15 12:37:53 +00:00
def testJsonld():
print("testJsonld")
2020-06-15 12:37:53 +00:00
jldDocument = {
"@context": "https://www.w3.org/ns/activitystreams",
"actor": "https://somesite.net/users/gerbil",
2020-06-15 12:37:53 +00:00
"description": "My json document",
"numberField": 83582,
"object": {
2021-01-03 14:34:27 +00:00
"content": "valid content"
2020-06-15 12:37:53 +00:00
}
}
# privateKeyPem, publicKeyPem = generateRSAKey()
privateKeyPem = '-----BEGIN RSA PRIVATE KEY-----\n' \
'MIIEowIBAAKCAQEAod9iHfIn4ugY/2byFrFjUprrFLkkH5bCrjiBq2/MdHFg99IQ\n' \
'7li2x2mg5fkBMhU5SJIxlN8kiZMFq7JUXSA97Yo4puhVubqTSHihIh6Xn2mTjTgs\n' \
'zNo9SBbmN3YiyBPTcr0rF4jGWZAduJ8u6i7Eky2QH+UBKyUNRZrcfoVq+7grHUIA\n' \
'45pE7vAfEEWtgRiw32Nwlx55N3hayHax0y8gMdKEF/vfYKRLcM7rZgEASMtlCpgy\n' \
'fsyHwFCDzl/BP8AhP9u3dM+SEundeAvF58AiXx1pKvBpxqttDNAsKWCRQ06/WI/W\n' \
'2Rwihl9yCjobqRoFsZ/cTEi6FG9AbDAds5YjTwIDAQABAoIBAERL3rbpy8Bl0t43\n' \
'jh7a+yAIMvVMZBxb3InrV3KAug/LInGNFQ2rKnsaawN8uu9pmwCuhfLc7yqIeJUH\n' \
'qaadCuPlNJ/fWQQC309tbfbaV3iv78xejjBkSATZfIqb8nLeQpGflMXaNG3na1LQ\n' \
'/tdZoiDC0ZNTaNnOSTo765oKKqhHUTQkwkGChrwG3Js5jekV4zpPMLhUafXk6ksd\n' \
'8XLlZdCF3RUnuguXAg2xP/duxMYmTCx3eeGPkXBPQl0pahu8/6OtBoYvBrqNdQcx\n' \
'jnEtYX9PCqDY3hAXW9GWsxNfu02DKhWigFHFNRUQtMI++438+QIfzXPslE2bTQIt\n' \
'0OXUlwECgYEAxTKUZ7lwIBb5XKPJq53RQmX66M3ArxI1RzFSKm1+/CmxvYiN0c+5\n' \
'2Aq62WEIauX6hoZ7yQb4zhdeNRzinLR7rsmBvIcP12FidXG37q9v3Vu70KmHniJE\n' \
'TPbt5lHQ0bNACFxkar4Ab/JZN4CkMRgJdlcZ5boYNmcGOYCvw9izuM8CgYEA0iQ1\n' \
'khIFZ6fCiXwVRGvEHmqSnkBmBHz8MY8fczv2Z4Gzfq3Tlh9VxpigK2F2pFt7keWc\n' \
'53HerYFHFpf5otDhEyRwA1LyIcwbj5HopumxsB2WG+/M2as45lLfWa6KO73OtPpU\n' \
'wGZYW+i/otdk9eFphceYtw19mxI+3lYoeI8EjYECgYBxOtTKJkmCs45lqkp/d3QT\n' \
'2zjSempcXGkpQuG6KPtUUaCUgxdj1RISQj792OCbeQh8PDZRvOYaeIKInthkQKIQ\n' \
'P/Z1yVvIQUvmwfBqZmQmR6k1bFLJ80UiqFr7+BiegH2RD3Q9cnIP1aly3DPrWLD+\n' \
'OY9OQKfsfQWu+PxzyTeRMwKBgD8Zjlh5PtQ8RKcB8mTkMzSq7bHFRpzsZtH+1wPE\n' \
'Kp40DRDp41H9wMTsiZPdJUH/EmDh4LaCs8nHuu/m3JfuPtd/pn7pBjntzwzSVFji\n' \
'bW+jwrJK1Gk8B87pbZXBWlLMEOi5Dn/je37Fqd2c7f0DHauFHq9AxsmsteIPXwGs\n' \
'eEKBAoGBAIzJX/5yFp3ObkPracIfOJ/U/HF1UdP6Y8qmOJBZOg5s9Y+JAdY76raK\n' \
'0SbZPsOpuFUdTiRkSI3w/p1IuM5dPxgCGH9MHqjqogU5QwXr3vLF+a/PFhINkn1x\n' \
'lozRZjDcF1y6xHfExotPC973UZnKEviq9/FqOsovZpvSQkzAYSZF\n' \
'-----END RSA PRIVATE KEY-----'
publicKeyPem = '-----BEGIN PUBLIC KEY-----\n' \
'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAod9iHfIn4ugY/2byFrFj\n' \
'UprrFLkkH5bCrjiBq2/MdHFg99IQ7li2x2mg5fkBMhU5SJIxlN8kiZMFq7JUXSA9\n' \
'7Yo4puhVubqTSHihIh6Xn2mTjTgszNo9SBbmN3YiyBPTcr0rF4jGWZAduJ8u6i7E\n' \
'ky2QH+UBKyUNRZrcfoVq+7grHUIA45pE7vAfEEWtgRiw32Nwlx55N3hayHax0y8g\n' \
'MdKEF/vfYKRLcM7rZgEASMtlCpgyfsyHwFCDzl/BP8AhP9u3dM+SEundeAvF58Ai\n' \
'Xx1pKvBpxqttDNAsKWCRQ06/WI/W2Rwihl9yCjobqRoFsZ/cTEi6FG9AbDAds5Yj\n' \
'TwIDAQAB\n' \
'-----END PUBLIC KEY-----'
signedDocument = jldDocument.copy()
generateJsonSignature(signedDocument, privateKeyPem)
2020-06-15 12:37:53 +00:00
assert(signedDocument)
2020-06-15 13:35:33 +00:00
assert(signedDocument.get('signature'))
assert(signedDocument['signature'].get('signatureValue'))
assert(signedDocument['signature'].get('type'))
assert(len(signedDocument['signature']['signatureValue']) > 50)
# print(str(signedDocument['signature']))
assert(signedDocument['signature']['type'] == 'RsaSignature2017')
assert(verifyJsonSignature(signedDocument, publicKeyPem))
# alter the signed document
signedDocument['object']['content'] = 'forged content'
assert(not verifyJsonSignature(signedDocument, publicKeyPem))
2020-06-15 12:37:53 +00:00
2021-01-03 15:27:59 +00:00
jldDocument2 = {
"@context": "https://www.w3.org/ns/activitystreams",
"actor": "https://somesite.net/users/gerbil",
2021-01-03 15:27:59 +00:00
"description": "Another json document",
"numberField": 13353,
"object": {
"content": "More content"
}
}
signedDocument2 = jldDocument2.copy()
generateJsonSignature(signedDocument2, privateKeyPem)
2021-01-03 15:27:59 +00:00
assert(signedDocument2)
assert(signedDocument2.get('signature'))
assert(signedDocument2['signature'].get('signatureValue'))
# changed signature on different document
if signedDocument['signature']['signatureValue'] == \
signedDocument2['signature']['signatureValue']:
print('json signature has not changed for different documents')
assert '.' not in str(signedDocument['signature']['signatureValue'])
assert len(str(signedDocument['signature']['signatureValue'])) > 340
assert(signedDocument['signature']['signatureValue'] !=
signedDocument2['signature']['signatureValue'])
2021-01-03 15:27:59 +00:00
2020-06-15 12:37:53 +00:00
2020-06-22 16:55:19 +00:00
def testSiteIsActive():
print('testSiteIsActive')
assert(siteIsActive('https://archive.org'))
2020-06-22 16:55:19 +00:00
assert(siteIsActive('https://mastodon.social'))
assert(not siteIsActive('https://notarealwebsite.a.b.c'))
def testRemoveHtml():
print('testRemoveHtml')
testStr = 'This string has no html.'
assert(removeHtml(testStr) == testStr)
testStr = 'This string <a href="1234.567">has html</a>.'
assert(removeHtml(testStr) == 'This string has html.')
2020-12-13 14:48:45 +00:00
def testDangerousCSS():
print('testDangerousCSS')
baseDir = os.getcwd()
for subdir, dirs, files in os.walk(baseDir):
for f in files:
if not f.endswith('.css'):
continue
assert not dangerousCSS(baseDir + '/' + f, False)
break
2020-07-10 14:15:01 +00:00
def testDangerousMarkup():
print('testDangerousMarkup')
allowLocalNetworkAccess = False
2020-07-10 14:15:01 +00:00
content = '<p>This is a valid message</p>'
assert(not dangerousMarkup(content, allowLocalNetworkAccess))
2020-11-11 09:42:48 +00:00
2020-07-10 14:15:01 +00:00
content = 'This is a valid message without markup'
assert(not dangerousMarkup(content, allowLocalNetworkAccess))
2020-11-11 09:42:48 +00:00
2020-07-10 14:15:01 +00:00
content = '<p>This is a valid-looking message. But wait... ' + \
'<script>document.getElementById("concentrated")' + \
'.innerHTML = "evil";</script></p>'
assert(dangerousMarkup(content, allowLocalNetworkAccess))
2020-11-11 09:42:48 +00:00
2020-11-15 10:36:24 +00:00
content = '<p>This html contains more than you expected... ' + \
'<script language="javascript">document.getElementById("abc")' + \
'.innerHTML = "def";</script></p>'
assert(dangerousMarkup(content, allowLocalNetworkAccess))
2020-11-15 10:36:24 +00:00
2020-07-10 14:15:01 +00:00
content = '<p>This is a valid-looking message. But wait... ' + \
'<script src="https://evilsite/payload.js" /></p>'
assert(dangerousMarkup(content, allowLocalNetworkAccess))
2020-11-11 09:42:48 +00:00
2020-07-10 14:15:01 +00:00
content = '<p>This message embeds an evil frame.' + \
'<iframe src="somesite"></iframe></p>'
assert(dangerousMarkup(content, allowLocalNetworkAccess))
2020-11-11 09:42:48 +00:00
2020-07-10 14:15:01 +00:00
content = '<p>This message tries to obfuscate an evil frame.' + \
'< iframe src = "somesite"></ iframe ></p>'
assert(dangerousMarkup(content, allowLocalNetworkAccess))
2020-11-11 09:42:48 +00:00
2020-07-10 14:15:01 +00:00
content = '<p>This message is not necessarily evil, but annoying.' + \
'<hr><br><br><br><br><br><br><br><hr><hr></p>'
assert(dangerousMarkup(content, allowLocalNetworkAccess))
2020-11-11 09:42:48 +00:00
2020-07-10 14:15:01 +00:00
content = '<p>This message contans a ' + \
'<a href="https://validsite/index.html">valid link.</a></p>'
assert(not dangerousMarkup(content, allowLocalNetworkAccess))
2020-11-11 09:42:48 +00:00
2020-07-10 14:15:01 +00:00
content = '<p>This message contans a ' + \
'<a href="https://validsite/iframe.html">' + \
'valid link having invalid but harmless name.</a></p>'
assert(not dangerousMarkup(content, allowLocalNetworkAccess))
2020-07-10 14:15:01 +00:00
2020-11-11 09:42:48 +00:00
content = '<p>This message which <a href="127.0.0.1:8736">' + \
'tries to access the local network</a></p>'
assert(dangerousMarkup(content, allowLocalNetworkAccess))
2020-11-11 09:42:48 +00:00
content = '<p>This message which <a href="http://192.168.5.10:7235">' + \
'tries to access the local network</a></p>'
assert(dangerousMarkup(content, allowLocalNetworkAccess))
2020-11-11 09:42:48 +00:00
content = '<p>127.0.0.1 This message which does not access ' + \
'the local network</a></p>'
assert(not dangerousMarkup(content, allowLocalNetworkAccess))
2020-11-11 09:42:48 +00:00
2020-07-10 14:15:01 +00:00
2020-08-02 17:01:12 +00:00
def runHtmlReplaceQuoteMarks():
print('htmlReplaceQuoteMarks')
testStr = 'The "cat" "sat" on the mat'
result = htmlReplaceQuoteMarks(testStr)
2020-08-02 18:09:50 +00:00
assert result == 'The “cat” “sat” on the mat'
2020-08-02 17:01:12 +00:00
testStr = 'The cat sat on the mat'
result = htmlReplaceQuoteMarks(testStr)
assert result == 'The cat sat on the mat'
testStr = '"hello"'
result = htmlReplaceQuoteMarks(testStr)
2020-08-02 18:09:50 +00:00
assert result == '“hello”'
2020-08-02 17:01:12 +00:00
2020-08-02 19:16:22 +00:00
testStr = '"hello" <a href="somesite.html">&quot;test&quot; html</a>'
2020-08-02 17:17:51 +00:00
result = htmlReplaceQuoteMarks(testStr)
2020-08-02 19:16:22 +00:00
assert result == '“hello” <a href="somesite.html">“test” html</a>'
2020-08-02 17:17:51 +00:00
2020-08-02 17:01:12 +00:00
2020-08-21 18:32:16 +00:00
def testJsonPostAllowsComments():
print('testJsonPostAllowsComments')
postJsonObject = {
"id": "123"
}
assert jsonPostAllowsComments(postJsonObject)
postJsonObject = {
"id": "123",
"commentsEnabled": False
}
assert not jsonPostAllowsComments(postJsonObject)
postJsonObject = {
"id": "123",
"commentsEnabled": True
}
assert jsonPostAllowsComments(postJsonObject)
postJsonObject = {
"id": "123",
"object": {
"commentsEnabled": True
}
}
assert jsonPostAllowsComments(postJsonObject)
postJsonObject = {
"id": "123",
"object": {
"commentsEnabled": False
}
}
assert not jsonPostAllowsComments(postJsonObject)
2020-08-23 11:13:35 +00:00
def testRemoveIdEnding():
print('testRemoveIdEnding')
testStr = 'https://activitypub.somedomain.net'
resultStr = removeIdEnding(testStr)
assert resultStr == 'https://activitypub.somedomain.net'
testStr = \
'https://activitypub.somedomain.net/users/foo/' + \
'statuses/34544814814/activity'
resultStr = removeIdEnding(testStr)
assert resultStr == \
'https://activitypub.somedomain.net/users/foo/statuses/34544814814'
testStr = \
'https://undo.somedomain.net/users/foo/statuses/34544814814/undo'
resultStr = removeIdEnding(testStr)
assert resultStr == \
'https://undo.somedomain.net/users/foo/statuses/34544814814'
testStr = \
'https://event.somedomain.net/users/foo/statuses/34544814814/event'
resultStr = removeIdEnding(testStr)
assert resultStr == \
'https://event.somedomain.net/users/foo/statuses/34544814814'
2020-08-25 19:35:55 +00:00
def testValidContentWarning():
print('testValidContentWarning')
resultStr = validContentWarning('Valid content warning')
assert resultStr == 'Valid content warning'
resultStr = validContentWarning('Invalid #content warning')
assert resultStr == 'Invalid content warning'
resultStr = \
validContentWarning('Invalid <a href="somesite">content warning</a>')
assert resultStr == 'Invalid content warning'
2020-08-26 18:21:57 +00:00
def testTranslations():
print('testTranslations')
languagesStr = ('ar', 'ca', 'cy', 'de', 'es', 'fr', 'ga',
'hi', 'it', 'ja', 'oc', 'pt', 'ru', 'zh')
# load all translations into a dict
langDict = {}
for lang in languagesStr:
langJson = loadJson('translations/' + lang + '.json')
2020-08-29 11:14:19 +00:00
if not langJson:
print('Missing language file ' +
'translations/' + lang + '.json')
2020-08-26 18:21:57 +00:00
assert langJson
langDict[lang] = langJson
# load english translations
translationsJson = loadJson('translations/en.json')
# test each english string exists in the other language files
for englishStr, translatedStr in translationsJson.items():
for lang in languagesStr:
langJson = langDict[lang]
if not langJson.get(englishStr):
print(englishStr + ' is missing from ' + lang + '.json')
assert langJson.get(englishStr)
def testConstantTimeStringCheck():
print('testConstantTimeStringCheck')
assert constantTimeStringCheck('testing', 'testing')
assert not constantTimeStringCheck('testing', '1234')
assert not constantTimeStringCheck('testing', '1234567')
itterations = 256
start = time.time()
for timingTest in range(itterations):
constantTimeStringCheck('nnjfbefefbsnjsdnvbcueftqfeuqfbqefnjeniwufgy',
'nnjfbefefbsnjsdnvbcueftqfeuqfbqefnjeniwufgy')
end = time.time()
avTime1 = ((end - start) * 1000000 / itterations)
# change a single character and observe timing difference
start = time.time()
for timingTest in range(itterations):
constantTimeStringCheck('nnjfbefefbsnjsdnvbcueftqfeuqfbqefnjeniwufgy',
'nnjfbefefbsnjsdnvbcueftqfeuqfbqeznjeniwufgy')
end = time.time()
avTime2 = ((end - start) * 1000000 / itterations)
timeDiffMicroseconds = abs(avTime2 - avTime1)
# time difference should be less than 10uS
2020-10-25 10:10:56 +00:00
assert int(timeDiffMicroseconds) < 10
# change multiple characters and observe timing difference
start = time.time()
for timingTest in range(itterations):
constantTimeStringCheck('nnjfbefefbsnjsdnvbcueftqfeuqfbqefnjeniwufgy',
'ano1befffbsn7sd3vbluef6qseuqfpqeznjgni9bfgi')
end = time.time()
avTime2 = ((end - start) * 1000000 / itterations)
timeDiffMicroseconds = abs(avTime2 - avTime1)
# time difference should be less than 10uS
2020-10-25 10:10:56 +00:00
assert int(timeDiffMicroseconds) < 10
def testReplaceEmailQuote():
print('testReplaceEmailQuote')
2020-09-14 09:41:44 +00:00
testStr = '<p>This content has no quote.</p>'
assert htmlReplaceEmailQuote(testStr) == testStr
2020-09-14 09:41:44 +00:00
testStr = '<p>This content has no quote.</p>' + \
'<p>With multiple</p><p>lines</p>'
assert htmlReplaceEmailQuote(testStr) == testStr
2020-09-14 11:30:56 +00:00
testStr = '<p>&quot;This is a quoted paragraph.&quot;</p>'
assert htmlReplaceEmailQuote(testStr) == \
'<p><blockquote>This is a quoted paragraph.</blockquote></p>'
testStr = "<p><span class=\"h-card\">" + \
"<a href=\"https://somewebsite/@nickname\" " + \
"class=\"u-url mention\">@<span>nickname</span></a></span> " + \
"<br />&gt; This is a quote</p><p>Some other text.</p>"
expectedStr = "<p><span class=\"h-card\">" + \
"<a href=\"https://somewebsite/@nickname\" " + \
"class=\"u-url mention\">@<span>nickname</span></a></span> " + \
"<br /><blockquote>This is a quote</blockquote></p>" + \
"<p>Some other text.</p>"
resultStr = htmlReplaceEmailQuote(testStr)
if resultStr != expectedStr:
2020-09-30 22:52:39 +00:00
print('Result: ' + str(resultStr))
print('Expect: ' + expectedStr)
assert resultStr == expectedStr
2020-09-14 10:25:12 +00:00
testStr = "<p>Some text:</p><p>&gt; first line-&gt;second line</p>" + \
"<p>Some question?</p>"
expectedStr = "<p>Some text:</p><p><blockquote>first line-<br>" + \
"second line</blockquote></p><p>Some question?</p>"
resultStr = htmlReplaceEmailQuote(testStr)
if resultStr != expectedStr:
2020-09-30 22:52:39 +00:00
print('Result: ' + str(resultStr))
2020-09-14 10:25:12 +00:00
print('Expect: ' + expectedStr)
assert resultStr == expectedStr
2020-09-30 22:22:42 +00:00
testStr = "<p><span class=\"h-card\">" + \
"<a href=\"https://somedomain/@somenick\" " + \
"class=\"u-url mention\">@<span>somenick</span>" + \
"</a></span> </p><p>&gt; Text1.<br />&gt; <br />" + \
"&gt; Text2<br />&gt; <br />&gt; Text3<br />" + \
"&gt;<br />&gt; Text4<br />&gt; <br />&gt; " + \
"Text5<br />&gt; <br />&gt; Text6</p><p>Text7</p>"
2020-09-30 22:55:53 +00:00
expectedStr = "<p><span class=\"h-card\">" + \
"<a href=\"https://somedomain/@somenick\" " + \
"class=\"u-url mention\">@<span>somenick</span></a>" + \
"</span> </p><p><blockquote> Text1.<br /><br />" + \
"Text2<br /><br />Text3<br />&gt;<br />Text4<br />" + \
"<br />Text5<br /><br />Text6</blockquote></p><p>Text7</p>"
2020-09-30 22:22:42 +00:00
resultStr = htmlReplaceEmailQuote(testStr)
if resultStr != expectedStr:
2020-09-30 22:52:39 +00:00
print('Result: ' + str(resultStr))
2020-09-30 22:22:42 +00:00
print('Expect: ' + expectedStr)
assert resultStr == expectedStr
2020-10-11 09:33:31 +00:00
def testRemoveHtmlTag():
print('testRemoveHtmlTag')
testStr = "<p><img width=\"864\" height=\"486\" " + \
"src=\"https://somesiteorother.com/image.jpg\"></p>"
resultStr = removeHtmlTag(testStr, 'width')
assert resultStr == "<p><img height=\"486\" " + \
"src=\"https://somesiteorother.com/image.jpg\"></p>"
2020-10-17 12:05:41 +00:00
def testHashtagRuleTree():
print('testHashtagRuleTree')
2020-10-20 17:37:15 +00:00
operators = ('not', 'and', 'or', 'xor', 'from', 'contains')
2020-10-17 12:05:41 +00:00
2020-10-20 17:37:15 +00:00
url = 'testsite.com'
2020-10-18 15:10:36 +00:00
moderated = True
conditionsStr = \
'contains "Cat" or contains "Corvid" or ' + \
'contains "Dormouse" or contains "Buzzard"'
tagsInConditions = []
tree = hashtagRuleTree(operators, conditionsStr,
tagsInConditions, moderated)
assert str(tree) == str(['or', ['contains', ['"Cat"']],
['contains', ['"Corvid"']],
['contains', ['"Dormouse"']],
['contains', ['"Buzzard"']]])
content = 'This is a test'
2020-10-17 17:36:10 +00:00
moderated = True
2020-10-17 12:05:41 +00:00
conditionsStr = '#foo or #bar'
tagsInConditions = []
2020-10-17 17:36:10 +00:00
tree = hashtagRuleTree(operators, conditionsStr,
tagsInConditions, moderated)
2020-10-17 12:05:41 +00:00
assert str(tree) == str(['or', ['#foo'], ['#bar']])
assert str(tagsInConditions) == str(['#foo', '#bar'])
hashtags = ['#foo']
2020-10-20 17:37:15 +00:00
assert hashtagRuleResolve(tree, hashtags, moderated, content, url)
2020-10-17 12:05:41 +00:00
hashtags = ['#carrot', '#stick']
2020-10-20 17:37:15 +00:00
assert not hashtagRuleResolve(tree, hashtags, moderated, content, url)
content = 'This is a test'
url = 'https://testsite.com/something'
moderated = True
conditionsStr = '#foo and from "testsite.com"'
tagsInConditions = []
tree = hashtagRuleTree(operators, conditionsStr,
tagsInConditions, moderated)
assert str(tree) == str(['and', ['#foo'], ['from', ['"testsite.com"']]])
assert str(tagsInConditions) == str(['#foo'])
hashtags = ['#foo']
2020-10-21 10:39:09 +00:00
assert hashtagRuleResolve(tree, hashtags, moderated, content, url)
2020-10-20 17:37:15 +00:00
assert not hashtagRuleResolve(tree, hashtags, moderated, content,
'othersite.net')
content = 'This is a test'
moderated = True
conditionsStr = 'contains "is a" and #foo or #bar'
tagsInConditions = []
tree = hashtagRuleTree(operators, conditionsStr,
tagsInConditions, moderated)
assert str(tree) == \
str(['and', ['contains', ['"is a"']],
['or', ['#foo'], ['#bar']]])
assert str(tagsInConditions) == str(['#foo', '#bar'])
hashtags = ['#foo']
2020-10-20 17:37:15 +00:00
assert hashtagRuleResolve(tree, hashtags, moderated, content, url)
hashtags = ['#carrot', '#stick']
2020-10-20 17:37:15 +00:00
assert not hashtagRuleResolve(tree, hashtags, moderated, content, url)
2020-10-17 17:36:10 +00:00
moderated = False
conditionsStr = 'not moderated and #foo or #bar'
tagsInConditions = []
tree = hashtagRuleTree(operators, conditionsStr,
tagsInConditions, moderated)
assert str(tree) == \
str(['not', ['and', ['moderated'], ['or', ['#foo'], ['#bar']]]])
assert str(tagsInConditions) == str(['#foo', '#bar'])
hashtags = ['#foo']
2020-10-20 17:37:15 +00:00
assert hashtagRuleResolve(tree, hashtags, moderated, content, url)
2020-10-17 17:36:10 +00:00
hashtags = ['#carrot', '#stick']
2020-10-20 17:37:15 +00:00
assert hashtagRuleResolve(tree, hashtags, moderated, content, url)
2020-10-17 17:36:10 +00:00
moderated = True
conditionsStr = 'moderated and #foo or #bar'
tagsInConditions = []
tree = hashtagRuleTree(operators, conditionsStr,
tagsInConditions, moderated)
assert str(tree) == \
str(['and', ['moderated'], ['or', ['#foo'], ['#bar']]])
assert str(tagsInConditions) == str(['#foo', '#bar'])
hashtags = ['#foo']
2020-10-20 17:37:15 +00:00
assert hashtagRuleResolve(tree, hashtags, moderated, content, url)
2020-10-17 17:36:10 +00:00
hashtags = ['#carrot', '#stick']
2020-10-20 17:37:15 +00:00
assert not hashtagRuleResolve(tree, hashtags, moderated, content, url)
2020-10-17 12:05:41 +00:00
conditionsStr = 'x'
tagsInConditions = []
2020-10-17 17:36:10 +00:00
tree = hashtagRuleTree(operators, conditionsStr,
tagsInConditions, moderated)
2020-10-17 12:05:41 +00:00
assert tree is None
assert tagsInConditions == []
hashtags = ['#foo']
2020-10-20 17:37:15 +00:00
assert not hashtagRuleResolve(tree, hashtags, moderated, content, url)
2020-10-17 12:05:41 +00:00
conditionsStr = '#x'
tagsInConditions = []
2020-10-17 17:36:10 +00:00
tree = hashtagRuleTree(operators, conditionsStr,
tagsInConditions, moderated)
2020-10-17 12:05:41 +00:00
assert str(tree) == str(['#x'])
assert str(tagsInConditions) == str(['#x'])
hashtags = ['#x']
2020-10-20 17:37:15 +00:00
assert hashtagRuleResolve(tree, hashtags, moderated, content, url)
2020-10-17 12:05:41 +00:00
hashtags = ['#y', '#z']
2020-10-20 17:37:15 +00:00
assert not hashtagRuleResolve(tree, hashtags, moderated, content, url)
2020-10-17 12:05:41 +00:00
conditionsStr = 'not #b'
tagsInConditions = []
2020-10-17 17:36:10 +00:00
tree = hashtagRuleTree(operators, conditionsStr,
tagsInConditions, moderated)
2020-10-17 12:05:41 +00:00
assert str(tree) == str(['not', ['#b']])
assert str(tagsInConditions) == str(['#b'])
hashtags = ['#y', '#z']
2020-10-20 17:37:15 +00:00
assert hashtagRuleResolve(tree, hashtags, moderated, content, url)
2020-10-17 12:05:41 +00:00
hashtags = ['#a', '#b', '#c']
2020-10-20 17:37:15 +00:00
assert not hashtagRuleResolve(tree, hashtags, moderated, content, url)
2020-10-17 12:05:41 +00:00
conditionsStr = '#foo or #bar and #a'
tagsInConditions = []
2020-10-17 17:36:10 +00:00
tree = hashtagRuleTree(operators, conditionsStr,
tagsInConditions, moderated)
2020-10-17 12:05:41 +00:00
assert str(tree) == str(['and', ['or', ['#foo'], ['#bar']], ['#a']])
assert str(tagsInConditions) == str(['#foo', '#bar', '#a'])
2020-10-18 15:10:36 +00:00
hashtags = ['#foo', '#bar', '#a']
2020-10-20 17:37:15 +00:00
assert hashtagRuleResolve(tree, hashtags, moderated, content, url)
2020-10-17 12:05:41 +00:00
hashtags = ['#bar', '#a']
2020-10-20 17:37:15 +00:00
assert hashtagRuleResolve(tree, hashtags, moderated, content, url)
2020-10-17 12:05:41 +00:00
hashtags = ['#foo', '#a']
2020-10-20 17:37:15 +00:00
assert hashtagRuleResolve(tree, hashtags, moderated, content, url)
2020-10-17 12:05:41 +00:00
hashtags = ['#x', '#a']
2020-10-20 17:37:15 +00:00
assert not hashtagRuleResolve(tree, hashtags, moderated, content, url)
2020-10-17 12:05:41 +00:00
2020-10-25 10:06:54 +00:00
def testGetNewswireTags():
print('testGetNewswireTags')
2020-10-25 10:24:02 +00:00
rssDescription = '<img src="https://somesite/someimage.jpg" ' + \
2020-10-25 10:08:02 +00:00
'class="misc-stuff" alt="#ExcitingHashtag" ' + \
'srcset="https://somesite/someimage.jpg" ' + \
'sizes="(max-width: 864px) 100vw, 864px" />' + \
'Compelling description with #ExcitingHashtag, which is ' + \
'being posted in #BoringForum'
2020-10-25 10:06:54 +00:00
tags = getNewswireTags(rssDescription, 10)
assert len(tags) == 2
assert '#BoringForum' in tags
assert '#ExcitingHashtag' in tags
2020-11-08 11:24:43 +00:00
def testFirstParagraphFromString():
print('testFirstParagraphFromString')
testStr = \
'<p><a href="https://somesite.com/somepath">This is a test</a></p>' + \
'<p>This is another paragraph</p>'
resultStr = firstParagraphFromString(testStr)
assert resultStr == 'This is a test'
testStr = 'Testing without html'
resultStr = firstParagraphFromString(testStr)
assert resultStr == testStr
2020-11-22 18:43:01 +00:00
def testParseFeedDate():
print('testParseFeedDate')
2020-12-09 10:38:09 +00:00
2020-12-14 15:17:30 +00:00
pubDate = "2020-12-14T00:08:06+00:00"
publishedDate = parseFeedDate(pubDate)
assert publishedDate == "2020-12-14 00:08:06+00:00"
2020-12-09 10:38:09 +00:00
pubDate = "Tue, 08 Dec 2020 06:24:38 -0600"
publishedDate = parseFeedDate(pubDate)
assert publishedDate == "2020-12-08 12:24:38+00:00"
2020-11-22 18:43:01 +00:00
pubDate = "2020-08-27T16:12:34+00:00"
publishedDate = parseFeedDate(pubDate)
2020-11-22 19:13:41 +00:00
assert publishedDate == "2020-08-27 16:12:34+00:00"
2020-11-22 19:01:18 +00:00
pubDate = "Sun, 22 Nov 2020 19:51:33 +0100"
publishedDate = parseFeedDate(pubDate)
2020-11-22 20:18:10 +00:00
assert publishedDate == "2020-11-22 18:51:33+00:00"
2020-11-22 18:43:01 +00:00
2020-11-24 10:53:10 +00:00
def testValidNickname():
print('testValidNickname')
domain = 'somedomain.net'
nickname = 'myvalidnick'
assert validNickname(domain, nickname)
nickname = 'my.invalid.nick'
assert not validNickname(domain, nickname)
nickname = 'myinvalidnick?'
assert not validNickname(domain, nickname)
nickname = 'my invalid nick?'
assert not validNickname(domain, nickname)
2020-12-05 11:11:32 +00:00
def testGuessHashtagCategory() -> None:
print('testGuessHashtagCategory')
hashtagCategories = {
"foo": ["swan", "goose"],
"bar": ["cat", "mouse"]
}
guess = guessHashtagCategory("unspecifiedgoose", hashtagCategories)
assert guess == "foo"
guess = guessHashtagCategory("catpic", hashtagCategories)
assert guess == "bar"
2020-12-13 19:05:26 +00:00
def testGetMentionedPeople() -> None:
print('testGetMentionedPeople')
baseDir = os.getcwd()
content = "@dragon@cave.site @bat@cave.site This is a test."
actors = getMentionedPeople(baseDir, 'https',
content,
'mydomain', False)
assert actors
assert len(actors) == 2
assert actors[0] == "https://cave.site/users/dragon"
assert actors[1] == "https://cave.site/users/bat"
2020-12-13 19:53:31 +00:00
def testReplyToPublicPost() -> None:
baseDir = os.getcwd()
nickname = 'test7492362'
domain = 'other.site'
port = 443
httpPrefix = 'https'
postId = httpPrefix + '://rat.site/users/ninjarodent/statuses/63746173435'
reply = \
createPublicPost(baseDir, nickname, domain, port, httpPrefix,
"@ninjarodent@rat.site This is a test.",
False, False, False, True,
None, None, False, postId)
2020-12-13 20:07:45 +00:00
# print(str(reply))
2020-12-13 19:53:31 +00:00
assert reply['object']['content'] == \
'<p><span class=\"h-card\">' + \
'<a href=\"https://rat.site/@ninjarodent\" ' + \
'class=\"u-url mention\">@<span>ninjarodent</span>' + \
'</a></span> This is a test.</p>'
assert reply['object']['tag'][0]['type'] == 'Mention'
assert reply['object']['tag'][0]['name'] == '@ninjarodent@rat.site'
assert reply['object']['tag'][0]['href'] == \
'https://rat.site/users/ninjarodent'
assert len(reply['object']['to']) == 1
assert reply['object']['to'][0].endswith('#Public')
assert len(reply['object']['cc']) >= 1
assert reply['object']['cc'][0].endswith(nickname + '/followers')
assert len(reply['object']['tag']) == 1
assert len(reply['object']['cc']) == 2
assert reply['object']['cc'][1] == \
httpPrefix + '://rat.site/users/ninjarodent'
def getFunctionCallArgs(name: str, lines: [], startLineCtr: int) -> []:
"""Returns the arguments of a function call given lines
of source code and a starting line number
2020-12-22 21:27:46 +00:00
"""
argsStr = lines[startLineCtr].split(name + '(')[1]
if ')' in argsStr:
argsStr = argsStr.split(')')[0].replace(' ', '').split(',')
return argsStr
for lineCtr in range(startLineCtr + 1, len(lines)):
if ')' not in lines[lineCtr]:
argsStr += lines[lineCtr]
continue
else:
argsStr += lines[lineCtr].split(')')[0]
break
return argsStr.replace('\n', '').replace(' ', '').split(',')
2020-12-22 22:55:45 +00:00
def getFunctionCalls(name: str, lines: [], startLineCtr: int,
functionProperties: {}) -> []:
"""Returns the functions called by the given one,
Starting with the given source code at the given line
"""
callsFunctions = []
functionContentStr = ''
for lineCtr in range(startLineCtr + 1, len(lines)):
2020-12-23 12:48:50 +00:00
lineStr = lines[lineCtr].strip()
if lineStr.startswith('def '):
2020-12-22 22:55:45 +00:00
break
2020-12-23 12:48:50 +00:00
if lineStr.startswith('class '):
2020-12-22 22:55:45 +00:00
break
functionContentStr += lines[lineCtr]
for funcName, properties in functionProperties.items():
if funcName + '(' in functionContentStr:
callsFunctions.append(funcName)
return callsFunctions
def functionArgsMatch(callArgs: [], funcArgs: []):
"""Do the function artuments match the function call arguments
"""
if len(callArgs) == len(funcArgs):
return True
# count non-optional arguments
callArgsCtr = 0
for a in callArgs:
if a == 'self':
continue
2020-12-23 12:48:50 +00:00
if '=' not in a or a.startswith("'"):
callArgsCtr += 1
funcArgsCtr = 0
for a in funcArgs:
if a == 'self':
continue
2020-12-23 12:48:50 +00:00
if '=' not in a or a.startswith("'"):
funcArgsCtr += 1
return callArgsCtr >= funcArgsCtr
def testFunctions():
print('testFunctions')
function = {}
functionProperties = {}
2020-12-22 19:28:34 +00:00
modules = {}
for subdir, dirs, files in os.walk('.'):
for sourceFile in files:
if not sourceFile.endswith('.py'):
continue
modName = sourceFile.replace('.py', '')
2020-12-22 19:28:34 +00:00
modules[modName] = {
'functions': []
}
sourceStr = ''
with open(sourceFile, "r") as f:
sourceStr = f.read()
2020-12-22 19:28:34 +00:00
modules[modName]['source'] = sourceStr
with open(sourceFile, "r") as f:
lines = f.readlines()
2020-12-22 19:28:34 +00:00
modules[modName]['lines'] = lines
for line in lines:
2020-12-23 12:48:50 +00:00
if not line.strip().startswith('def '):
continue
methodName = line.split('def ', 1)[1].split('(')[0]
methodArgs = \
sourceStr.split('def ' + methodName + '(')[1]
methodArgs = methodArgs.split(')')[0]
methodArgs = methodArgs.replace(' ', '').split(',')
if function.get(modName):
function[modName].append(methodName)
else:
function[modName] = [methodName]
2020-12-22 19:28:34 +00:00
if methodName not in modules[modName]['functions']:
modules[modName]['functions'].append(methodName)
functionProperties[methodName] = {
"args": methodArgs,
"module": modName,
"calledInModule": []
}
break
excludeFuncArgs = [
'pyjsonld'
]
excludeFuncs = [
2020-12-23 12:48:50 +00:00
'link',
'set',
'get'
]
# which modules is each function used within?
2020-12-22 19:28:34 +00:00
for modName, modProperties in modules.items():
2020-12-22 13:04:49 +00:00
print('Module: ' + modName + '')
2020-12-22 19:28:34 +00:00
for name, properties in functionProperties.items():
lineCtr = 0
2020-12-22 19:28:34 +00:00
for line in modules[modName]['lines']:
2020-12-23 12:48:50 +00:00
lineStr = line.strip()
if lineStr.startswith('def '):
lineCtr += 1
continue
if lineStr.startswith('class '):
lineCtr += 1
2020-12-22 19:28:34 +00:00
continue
if name + '(' in line:
modList = \
functionProperties[name]['calledInModule']
if modName not in modList:
modList.append(modName)
if modName in excludeFuncArgs:
lineCtr += 1
continue
if name in excludeFuncs:
lineCtr += 1
continue
callArgs = \
getFunctionCallArgs(name,
modules[modName]['lines'],
lineCtr)
if not functionArgsMatch(callArgs,
functionProperties[name]['args']):
print('Call to function ' + name +
' does not match its arguments')
print('def args: ' +
str(len(functionProperties[name]['args'])) +
'\n' + str(functionProperties[name]['args']))
print('Call args: ' + str(len(callArgs)) + '\n' +
str(callArgs))
print('module ' + modName + ' line ' + str(lineCtr))
assert False
lineCtr += 1
# don't check these functions, because they are procedurally called
exclusions = [
2020-12-23 12:48:50 +00:00
'do_GET',
'do_POST',
'do_HEAD',
'__run',
'globaltrace',
'localtrace',
'kill',
'clone',
'unregister_rdf_parser',
'set_document_loader',
2020-12-23 12:48:50 +00:00
'has_property',
'has_value',
'add_value',
'get_values',
'remove_property',
'remove_value',
'normalize',
'get_document_loader',
'runInboxQueueWatchdog',
'runInboxQueue',
'runPostSchedule',
'runPostScheduleWatchdog',
'str2bool',
'runNewswireDaemon',
'runNewswireWatchdog',
'threadSendPost',
'sendToFollowers',
'expireCache',
'getMutualsOfPerson',
'runPostsQueue',
'runSharesExpire',
'runPostsWatchdog',
'runSharesExpireWatchdog',
'getThisWeeksEvents',
'getAvailability',
'testThreadsFunction',
'createServerAlice',
'createServerBob',
'createServerEve',
'E2EEremoveDevice',
'setOrganizationScheme',
2021-03-04 14:36:24 +00:00
'fill_headers',
'_nothing'
]
2020-12-22 13:57:24 +00:00
excludeImports = [
2020-12-23 12:48:50 +00:00
'link',
'start'
2020-12-22 13:57:24 +00:00
]
excludeLocal = [
'pyjsonld',
'daemon',
'tests'
]
2020-12-23 12:48:50 +00:00
excludeMods = [
'pyjsonld'
]
# check that functions are called somewhere
for name, properties in functionProperties.items():
2020-12-23 12:48:50 +00:00
if name.startswith('__'):
if name.endswith('__'):
continue
if name in exclusions:
continue
2020-12-23 12:48:50 +00:00
if properties['module'] in excludeMods:
continue
2020-12-22 18:20:32 +00:00
isLocalFunction = False
if not properties['calledInModule']:
print('function ' + name +
' in module ' + properties['module'] +
' is not called anywhere')
assert properties['calledInModule']
if len(properties['calledInModule']) == 1:
modName = properties['calledInModule'][0]
if modName not in excludeLocal and \
modName == properties['module']:
2020-12-22 18:20:32 +00:00
isLocalFunction = True
if not name.startswith('_'):
print('Local function ' + name +
' in ' + modName + '.py does not begin with _')
assert False
2020-12-22 13:57:24 +00:00
if name not in excludeImports:
for modName in properties['calledInModule']:
if modName == properties['module']:
continue
importStr = 'from ' + properties['module'] + ' import ' + name
2020-12-22 19:28:34 +00:00
if importStr not in modules[modName]['source']:
2020-12-22 13:57:24 +00:00
print(importStr + ' not found in ' + modName + '.py')
assert False
2020-12-22 18:20:32 +00:00
if not isLocalFunction:
if name.startswith('_'):
excludePublic = [
'pyjsonld',
'daemon',
'tests'
]
modName = properties['module']
if modName not in excludePublic:
print('Public function ' + name + ' in ' +
modName + '.py begins with _')
assert False
2020-12-22 13:04:49 +00:00
print('Function: ' + name + '')
2020-12-23 16:19:18 +00:00
print('Constructing function call graph')
2020-12-23 18:15:30 +00:00
moduleColors = ('red', 'green', 'yellow', 'orange', 'purple', 'cyan',
'darkgoldenrod3', 'darkolivegreen1', 'darkorange1',
'darkorchid1', 'darkseagreen', 'darkslategray4',
'deeppink1', 'deepskyblue1', 'dimgrey', 'gold1',
'goldenrod', 'burlywood2', 'bisque1', 'brown1',
'chartreuse2', 'cornsilk', 'darksalmon')
2020-12-23 17:56:25 +00:00
maxModuleCalls = 1
2020-12-23 19:55:51 +00:00
maxFunctionCalls = 1
2020-12-23 18:15:30 +00:00
colorCtr = 0
2020-12-22 22:55:45 +00:00
for modName, modProperties in modules.items():
lineCtr = 0
2020-12-23 18:15:30 +00:00
modules[modName]['color'] = moduleColors[colorCtr]
colorCtr += 1
if colorCtr >= len(moduleColors):
colorCtr = 0
2020-12-22 22:55:45 +00:00
for line in modules[modName]['lines']:
2020-12-23 12:48:50 +00:00
if line.strip().startswith('def '):
2020-12-22 22:55:45 +00:00
name = line.split('def ')[1].split('(')[0]
callsList = \
getFunctionCalls(name, modules[modName]['lines'],
lineCtr, functionProperties)
functionProperties[name]['calls'] = callsList.copy()
2020-12-23 19:55:51 +00:00
if len(callsList) > maxFunctionCalls:
maxFunctionCalls = len(callsList)
2020-12-23 16:19:18 +00:00
# keep track of which module calls which other module
for fn in callsList:
modCall = functionProperties[fn]['module']
if modCall != modName:
if modules[modName].get('calls'):
if modCall not in modules[modName]['calls']:
modules[modName]['calls'].append(modCall)
2020-12-23 17:56:25 +00:00
if len(modules[modName]['calls']) > \
maxModuleCalls:
maxModuleCalls = \
len(modules[modName]['calls'])
2020-12-23 16:19:18 +00:00
else:
modules[modName]['calls'] = [modCall]
2020-12-22 22:55:45 +00:00
lineCtr += 1
2020-12-23 16:19:18 +00:00
callGraphStr = 'digraph EpicyonModules {\n\n'
callGraphStr += ' graph [fontsize=10 fontname="Verdana" compound=true];\n'
callGraphStr += ' node [shape=record fontsize=10 fontname="Verdana"];\n\n'
2020-12-23 17:56:25 +00:00
# colors of modules nodes
for modName, modProperties in modules.items():
if not modProperties.get('calls'):
callGraphStr += ' "' + modName + \
2020-12-23 19:55:51 +00:00
'" [fillcolor=yellow style=filled];\n'
2020-12-23 17:56:25 +00:00
continue
2020-12-23 19:55:51 +00:00
if len(modProperties['calls']) <= int(maxModuleCalls / 8):
2020-12-23 17:56:25 +00:00
callGraphStr += ' "' + modName + \
2020-12-23 19:55:51 +00:00
'" [fillcolor=green style=filled];\n'
elif len(modProperties['calls']) < int(maxModuleCalls / 4):
callGraphStr += ' "' + modName + \
'" [fillcolor=orange style=filled];\n'
2020-12-23 17:56:25 +00:00
else:
callGraphStr += ' "' + modName + \
2020-12-23 19:55:51 +00:00
'" [fillcolor=red style=filled];\n'
2020-12-23 17:56:25 +00:00
callGraphStr += '\n'
# connections between modules
2020-12-23 16:19:18 +00:00
for modName, modProperties in modules.items():
if not modProperties.get('calls'):
continue
for modCall in modProperties['calls']:
callGraphStr += ' "' + modName + '" -> "' + modCall + '";\n'
callGraphStr += '\n}\n'
with open('epicyon_modules.dot', 'w+') as fp:
fp.write(callGraphStr)
print('Modules call graph saved to epicyon_modules.dot')
print('Plot using: ' +
'sfdp -x -Goverlap=false -Goverlap_scaling=2 ' +
'-Gsep=+100 -Tx11 epicyon_modules.dot')
2020-12-22 22:55:45 +00:00
callGraphStr = 'digraph Epicyon {\n\n'
2020-12-23 16:19:18 +00:00
callGraphStr += ' size="8,6"; ratio=fill;\n'
2020-12-22 22:55:45 +00:00
callGraphStr += ' graph [fontsize=10 fontname="Verdana" compound=true];\n'
callGraphStr += ' node [shape=record fontsize=10 fontname="Verdana"];\n\n'
for modName, modProperties in modules.items():
2020-12-22 23:26:09 +00:00
callGraphStr += ' subgraph cluster_' + modName + ' {\n'
callGraphStr += ' label = "' + modName + '";\n'
2020-12-23 19:55:51 +00:00
callGraphStr += ' node [style=filled];\n'
2020-12-23 13:41:54 +00:00
moduleFunctionsStr = ''
2020-12-22 22:55:45 +00:00
for name in modProperties['functions']:
2020-12-23 14:19:06 +00:00
if name.startswith('test'):
continue
2020-12-23 13:41:54 +00:00
if name not in excludeFuncs:
2020-12-23 19:55:51 +00:00
if not functionProperties[name]['calls']:
moduleFunctionsStr += \
' "' + name + '" [fillcolor=yellow style=filled];\n'
continue
noOfCalls = len(functionProperties[name]['calls'])
if noOfCalls < int(maxFunctionCalls / 4):
moduleFunctionsStr += ' "' + name + \
'" [fillcolor=orange style=filled];\n'
else:
moduleFunctionsStr += ' "' + name + \
'" [fillcolor=red style=filled];\n'
2020-12-23 13:41:54 +00:00
if moduleFunctionsStr:
2020-12-23 19:55:51 +00:00
callGraphStr += moduleFunctionsStr + '\n'
2020-12-22 22:55:45 +00:00
callGraphStr += ' color=blue;\n'
callGraphStr += ' }\n\n'
for name, properties in functionProperties.items():
if not properties['calls']:
continue
2020-12-23 19:55:51 +00:00
noOfCalls = len(properties['calls'])
if noOfCalls <= int(maxFunctionCalls / 8):
modColor = 'blue'
elif noOfCalls < int(maxFunctionCalls / 4):
modColor = 'green'
else:
modColor = 'red'
2020-12-22 23:26:09 +00:00
for calledFunc in properties['calls']:
2020-12-23 14:19:06 +00:00
if calledFunc.startswith('test'):
continue
2020-12-23 13:41:54 +00:00
if calledFunc not in excludeFuncs:
2020-12-23 18:15:30 +00:00
callGraphStr += ' "' + name + '" -> "' + calledFunc + \
'" [color=' + modColor + '];\n'
2020-12-22 22:55:45 +00:00
callGraphStr += '\n}\n'
with open('epicyon.dot', 'w+') as fp:
fp.write(callGraphStr)
print('Call graph saved to epicyon.dot')
2020-12-23 16:19:18 +00:00
print('Plot using: ' +
2020-12-23 13:41:54 +00:00
'sfdp -x -Goverlap=prism -Goverlap_scaling=8 ' +
'-Gsep=+120 -Tx11 epicyon.dot')
2020-12-22 22:55:45 +00:00
2021-01-02 10:37:19 +00:00
def testLinksWithinPost() -> None:
baseDir = os.getcwd()
nickname = 'test27636'
domain = 'rando.site'
port = 443
httpPrefix = 'https'
content = 'This is a test post with links.\n\n' + \
'ftp://ftp.ncdc.noaa.gov/pub/data/ghcn/v4/\n\nhttps://freedombone.net'
postJsonObject = \
createPublicPost(baseDir, nickname, domain, port, httpPrefix,
content,
False, False, False, True,
None, None, False, None)
assert postJsonObject['object']['content'] == \
'<p>This is a test post with links.<br><br>' + \
'<a href="ftp://ftp.ncdc.noaa.gov/pub/data/ghcn/v4/" ' + \
'rel="nofollow noopener noreferrer" target="_blank">' + \
'<span class="invisible">ftp://</span>' + \
'<span class="ellipsis">' + \
'ftp.ncdc.noaa.gov/pub/data/ghcn/v4/</span>' + \
'</a><br><br><a href="https://freedombone.net" ' + \
'rel="nofollow noopener noreferrer" target="_blank">' + \
'<span class="invisible">https://</span>' + \
'<span class="ellipsis">freedombone.net</span></a></p>'
2021-01-05 23:09:04 +00:00
content = "<p>Some text</p><p>Other text</p><p>More text</p>" + \
"<pre><code>Errno::EOHNOES (No such file or rodent @ " + \
"ik_right - /tmp/blah.png)<br></code></pre><p>" + \
"(<a href=\"https://welllookeyhere.maam/error.txt\" " + \
"rel=\"nofollow noopener noreferrer\" target=\"_blank\">" + \
"wuh</a>)</p><p>Oh yeah like for sure</p>" + \
"<p>Ground sloth tin opener</p>" + \
"<p><a href=\"https://whocodedthis.huh/tags/" + \
"taggedthing\" class=\"mention hashtag\" rel=\"tag\" " + \
"target=\"_blank\">#<span>taggedthing</span></a></p>"
postJsonObject = \
createPublicPost(baseDir, nickname, domain, port, httpPrefix,
content,
False, False, False, True,
None, None, False, None)
assert postJsonObject['object']['content'] == content
2021-01-02 10:37:19 +00:00
2021-01-22 13:32:37 +00:00
def testMastoApi():
print('testMastoApi')
nickname = 'ThisIsATestNickname'
mastoId = getMastoApiV1IdFromNickname(nickname)
assert(mastoId)
nickname2 = getNicknameFromMastoApiV1Id(mastoId)
if nickname2 != nickname:
print(nickname + ' != ' + nickname2)
assert nickname2 == nickname
def testDomainHandling():
print('testDomainHandling')
testDomain = 'localhost'
assert decodedHost(testDomain) == testDomain
testDomain = '127.0.0.1:60'
assert decodedHost(testDomain) == testDomain
testDomain = '192.168.5.153'
assert decodedHost(testDomain) == testDomain
testDomain = 'xn--espaa-rta.icom.museum'
assert decodedHost(testDomain) == "españa.icom.museum"
2021-02-02 21:08:33 +00:00
def testPrepareHtmlPostNickname():
print('testPrepareHtmlPostNickname')
postHtml = '<a class="imageAnchor" href="/users/bob?replyfollowers='
postHtml += '<a class="imageAnchor" href="/users/bob?repeatprivate='
result = prepareHtmlPostNickname('alice', postHtml)
assert result == postHtml.replace('/bob?', '/alice?')
postHtml = '<a class="imageAnchor" href="/users/bob?replyfollowers='
postHtml += '<a class="imageAnchor" href="/users/bob;repeatprivate='
expectedHtml = '<a class="imageAnchor" href="/users/alice?replyfollowers='
expectedHtml += '<a class="imageAnchor" href="/users/bob;repeatprivate='
result = prepareHtmlPostNickname('alice', postHtml)
assert result == expectedHtml
def testValidHashTag():
print('testValidHashTag')
assert validHashTag('ThisIsValid')
assert validHashTag('ThisIsValid12345')
assert validHashTag('ThisIsVälid')
assert validHashTag('यहमान्यहै')
assert not validHashTag('ThisIsNotValid!')
assert not validHashTag('#ThisIsAlsoNotValid')
assert not validHashTag('#यहमान्यहै')
assert not validHashTag('ThisIsAlso&NotValid')
assert not validHashTag('ThisIsAlsoNotValid"')
assert not validHashTag('This Is Also Not Valid"')
assert not validHashTag('This=IsAlsoNotValid"')
2021-02-24 20:37:59 +00:00
def testMarkdownToHtml():
print('testMarkdownToHtml')
markdown = 'This is just plain text'
assert markdownToHtml(markdown) == markdown
2021-02-26 23:00:06 +00:00
markdown = 'This is a quotation:\n' + \
'> Some quote or other'
assert markdownToHtml(markdown) == 'This is a quotation:<br>' + \
'<blockquote><i>Some quote or other</i></blockquote>'
2021-02-26 23:13:33 +00:00
markdown = 'This is a multi-line quotation:\n' + \
'> The first line\n' + \
'> The second line'
assert markdownToHtml(markdown) == \
'This is a multi-line quotation:<br>' + \
'<blockquote><i>The first line The second line</i></blockquote>'
2021-02-25 10:54:38 +00:00
markdown = 'This is **bold**'
assert markdownToHtml(markdown) == 'This is <b>bold</b>'
markdown = 'This is *italic*'
assert markdownToHtml(markdown) == 'This is <i>italic</i>'
markdown = 'This is _underlined_'
assert markdownToHtml(markdown) == 'This is <ul>underlined</ul>'
markdown = 'This is **just** plain text'
assert markdownToHtml(markdown) == 'This is <b>just</b> plain text'
2021-02-24 20:37:59 +00:00
markdown = '# Title1\n### Title3\n## Title2\n'
assert markdownToHtml(markdown) == \
2021-02-24 21:17:08 +00:00
'<h1>Title1</h1><h3>Title3</h3><h2>Title2</h2>'
2021-02-24 20:37:59 +00:00
markdown = \
2021-02-25 10:54:38 +00:00
'This is [a link](https://something.somewhere) to something.\n' + \
2021-02-26 15:20:43 +00:00
'And [something else](https://cat.pic).\n' + \
'Or ![pounce](/cat.jpg).'
2021-02-24 20:37:59 +00:00
assert markdownToHtml(markdown) == \
'This is <a href="https://something.somewhere" ' + \
'target="_blank" rel="nofollow noopener noreferrer">' + \
2021-02-25 10:54:38 +00:00
'a link</a> to something.<br>' + \
2021-02-24 20:37:59 +00:00
'And <a href="https://cat.pic" ' + \
'target="_blank" rel="nofollow noopener noreferrer">' + \
2021-02-26 15:20:43 +00:00
'something else</a>.<br>' + \
'Or <img class="markdownImage" src="/cat.jpg" alt="pounce" />.'
2021-02-24 20:37:59 +00:00
def testExtractTextFieldsInPOST():
print('testExtractTextFieldsInPOST')
boundary = '-----------------------------116202748023898664511855843036'
formData = '-----------------------------116202748023898664511855' + \
'843036\r\nContent-Disposition: form-data; name="submitPost"' + \
'\r\n\r\nSubmit\r\n-----------------------------116202748023' + \
'898664511855843036\r\nContent-Disposition: form-data; name=' + \
'"subject"\r\n\r\n\r\n-----------------------------116202748' + \
'023898664511855843036\r\nContent-Disposition: form-data; na' + \
'me="message"\r\n\r\nThis is a ; test\r\n-------------------' + \
'----------116202748023898664511855843036\r\nContent-Disposi' + \
'tion: form-data; name="commentsEnabled"\r\n\r\non\r\n------' + \
'-----------------------116202748023898664511855843036\r\nCo' + \
'ntent-Disposition: form-data; name="eventDate"\r\n\r\n\r\n' + \
'-----------------------------116202748023898664511855843036' + \
'\r\nContent-Disposition: form-data; name="eventTime"\r\n\r' + \
'\n\r\n-----------------------------116202748023898664511855' + \
'843036\r\nContent-Disposition: form-data; name="location"' + \
'\r\n\r\n\r\n-----------------------------116202748023898664' + \
'511855843036\r\nContent-Disposition: form-data; name=' + \
'"imageDescription"\r\n\r\n\r\n-----------------------------' + \
'116202748023898664511855843036\r\nContent-Disposition: ' + \
'form-data; name="attachpic"; filename=""\r\nContent-Type: ' + \
'application/octet-stream\r\n\r\n\r\n----------------------' + \
'-------116202748023898664511855843036--\r\n'
debug = False
fields = extractTextFieldsInPOST(None, boundary, debug, formData)
assert fields['submitPost'] == 'Submit'
assert fields['subject'] == ''
assert fields['commentsEnabled'] == 'on'
assert fields['eventDate'] == ''
assert fields['eventTime'] == ''
assert fields['location'] == ''
assert fields['imageDescription'] == ''
assert fields['message'] == 'This is a ; test'
def testSpeakerReplaceLinks():
print('testSpeakerReplaceLinks')
text = 'The Tor Project: For Snowflake volunteers: If you use ' + \
'Firefox, Brave, or Chrome, our Snowflake extension turns ' + \
'your browser into a proxy that connects Tor users in ' + \
'censored regions to the Tor network. Note: you should ' + \
'not run more than one snowflake in the same ' + \
'network.https://support.torproject.org/censorship/' + \
'how-to-help-running-snowflake/'
detectedLinks = []
result = speakerReplaceLinks(text, {'Linked': 'Web link'}, detectedLinks)
print(result)
print(str(detectedLinks))
assert len(detectedLinks) == 1
assert detectedLinks[0] == \
'https://support.torproject.org/censorship/' + \
'how-to-help-running-snowflake/'
assert 'Web link support.torproject.org' in result
def testCamelCaseSplit():
print('testCamelCaseSplit')
testStr = 'ThisIsCamelCase'
assert camelCaseSplit(testStr) == 'This Is Camel Case'
testStr = 'Notcamelcase test'
assert camelCaseSplit(testStr) == 'Notcamelcase test'
2021-03-08 18:47:55 +00:00
def testEmojiImages():
print('testEmojiImages')
emojiFilename = 'emoji/default_emoji.json'
assert os.path.isfile(emojiFilename)
emojiJson = loadJson(emojiFilename)
assert emojiJson
for emojiName, emojiImage in emojiJson.items():
emojiImageFilename = 'emoji/' + emojiImage + '.png'
if not os.path.isfile(emojiImageFilename):
print('Missing emoji image ' + emojiName + ' ' +
emojiImage + '.png')
assert os.path.isfile(emojiImageFilename)
def testExtractPGPPublicKey():
print('testExtractPGPPublicKey')
pubKey = \
2021-03-11 17:15:32 +00:00
'-----BEGIN PGP PUBLIC KEY BLOCK-----\n\n' + \
'mDMEWZBueBYJKwYBBAHaRw8BAQdAKx1t6wL0RTuU6/' + \
'IBjngMbVJJ3Wg/3UW73/PV\n' + \
'I47xKTS0IUJvYiBNb3R0cmFtIDxib2JAZnJlZWRvb' + \
'WJvbmUubmV0PoiQBBMWCAA4\n' + \
'FiEEmruCwAq/OfgmgEh9zCU2GR+nwz8FAlmQbngCG' + \
'wMFCwkIBwMFFQoJCAsFFgID\n' + \
'AQACHgECF4AACgkQzCU2GR+nwz/9sAD/YgsHnVszH' + \
'Nz1zlVc5EgY1ByDupiJpHj0\n' + \
'XsLYk3AbNRgBALn45RqgD4eWHpmOriH09H5Rc5V9i' + \
'N4+OiGUn2AzJ6oHuDgEWZBu\n' + \
'eBIKKwYBBAGXVQEFAQEHQPRBG2ZQJce475S3e0Dxe' + \
'b0Fz5WdEu2q3GYLo4QG+4Ry\n' + \
'AwEIB4h4BBgWCAAgFiEEmruCwAq/OfgmgEh9zCU2G' + \
'R+nwz8FAlmQbngCGwwACgkQ\n' + \
'zCU2GR+nwz+OswD+JOoyBku9FzuWoVoOevU2HH+bP' + \
'OMDgY2OLnST9ZSyHkMBAMcK\n' + \
'fnaZ2Wi050483Sj2RmQRpb99Dod7rVZTDtCqXk0J\n' + \
'=gv5G\n' + \
'-----END PGP PUBLIC KEY BLOCK-----'
testStr = "Some introduction\n\n" + pubKey + "\n\nSome message."
assert containsPGPPublicKey(testStr)
assert not containsPGPPublicKey('String without a pgp key')
result = extractPGPPublicKey(testStr)
assert result
assert result == pubKey
2019-06-30 21:20:02 +00:00
def runAllTests():
print('Running tests...')
testFunctions()
testExtractPGPPublicKey()
2021-03-08 18:47:55 +00:00
testEmojiImages()
testCamelCaseSplit()
testSpeakerReplaceLinks()
testExtractTextFieldsInPOST()
2021-02-24 20:37:59 +00:00
testMarkdownToHtml()
testValidHashTag()
2021-02-02 21:08:33 +00:00
testPrepareHtmlPostNickname()
testDomainHandling()
2021-01-22 13:32:37 +00:00
testMastoApi()
2021-01-02 10:37:19 +00:00
testLinksWithinPost()
2020-12-13 19:53:31 +00:00
testReplyToPublicPost()
2020-12-13 19:05:26 +00:00
testGetMentionedPeople()
2020-12-05 11:11:32 +00:00
testGuessHashtagCategory()
2020-11-24 10:53:10 +00:00
testValidNickname()
2020-11-22 18:43:01 +00:00
testParseFeedDate()
2020-11-08 11:24:43 +00:00
testFirstParagraphFromString()
2020-10-25 10:06:54 +00:00
testGetNewswireTags()
2020-10-17 12:05:41 +00:00
testHashtagRuleTree()
2020-10-11 09:33:31 +00:00
testRemoveHtmlTag()
testReplaceEmailQuote()
testConstantTimeStringCheck()
2020-08-26 18:21:57 +00:00
testTranslations()
2020-08-25 19:35:55 +00:00
testValidContentWarning()
2020-08-23 11:13:35 +00:00
testRemoveIdEnding()
2020-08-21 18:32:16 +00:00
testJsonPostAllowsComments()
2020-08-02 17:01:12 +00:00
runHtmlReplaceQuoteMarks()
2020-12-13 14:48:45 +00:00
testDangerousCSS()
2020-07-10 14:15:01 +00:00
testDangerousMarkup()
testRemoveHtml()
2020-06-22 16:55:19 +00:00
testSiteIsActive()
2020-06-15 12:37:53 +00:00
testJsonld()
testRemoveTextFormatting()
2020-01-24 11:27:12 +00:00
testWebLinks()
testRecentPostsCache()
2019-11-23 13:04:11 +00:00
testTheme()
2019-11-23 10:13:57 +00:00
testSaveLoadJson()
2020-10-11 12:41:15 +00:00
testJsonString()
2019-10-12 12:45:53 +00:00
testGetStatusNumber()
2020-02-21 15:09:31 +00:00
testAddEmoji()
2019-08-21 16:35:46 +00:00
testActorParsing()
2019-06-30 21:20:02 +00:00
testHttpsig()
testHttpSigNew()
2019-06-30 21:20:02 +00:00
testCache()
testThreads()
2019-07-03 10:04:23 +00:00
testCreatePerson()
2019-07-03 18:24:44 +00:00
testAuthentication()
testFollowersOfPerson()
testNoOfFollowersOnDomain()
testFollows()
testGroupFollowers()
2019-07-18 16:21:26 +00:00
testDelegateRoles()
2020-03-22 21:16:02 +00:00
print('Tests succeeded\n')