Fixing tests

master
Bob Mottram 2019-08-18 10:39:12 +01:00
parent 0f01a5a11a
commit f8cc1873d4
7 changed files with 272 additions and 20 deletions

View File

@ -93,11 +93,17 @@ def acceptFollow(baseDir: str,domain : str,messageJson: {}, \
if debug:
print('DEBUG: No "to" parameter in follow Accept')
return
if len(messageJson['object']['to'])!=1:
if debug:
print('DEBUG: "to" does not contain a single recipient')
print(str(messageJson['object']['to']))
return
#if len(messageJson['object']['to'])!=1:
# if debug:
# print('DEBUG: "to" does not contain a single recipient')
# print(str(messageJson['object']['to']))
# if messageJson['object'].get('object'):
# if not isinstance(messageJson['object']['object'], str):
# messageJson['object']['to']=messageJson['object']['object']
# else:
# return
# else:
# return
if debug:
print('DEBUG: follow Accept received')
thisActor=messageJson['object']['actor']

View File

@ -42,6 +42,7 @@ from posts import createUnlistedPost
from posts import createFollowersOnlyPost
from posts import createDirectMessagePost
from posts import populateRepliesJson
from posts import addToField
from inbox import inboxPermittedMessage
from inbox import inboxMessageHasParams
from inbox import runInboxQueue
@ -405,7 +406,12 @@ class PubServer(BaseHTTPRequestHandler):
headersDict['digest']=self.headers['digest']
if self.headers.get('Content-type'):
headersDict['Content-type']=self.headers['Content-type']
# For follow activities add a 'to' field, which is a copy of the object field
messageJson,toFieldExists=addToField('Follow',messageJson,self.server.debug)
pprint(messageJson)
# save the json for later queue processing
queueFilename = \
savePostToInboxQueue(self.server.baseDir,
@ -2460,7 +2466,8 @@ class PubServer(BaseHTTPRequestHandler):
if self.server.debug:
print(followerNickname+' stops following '+followingActor)
followActor=self.server.httpPrefix+'://'+self.server.domainFull+'/users/'+followerNickname
followId=followActor+'#follows/'+followingNickname
statusNumber,published = getStatusNumber()
followId=followActor+'/statuses/'+str(statusNumber)
unfollowJson = {
'@context': 'https://www.w3.org/ns/activitystreams',
'id': followId+'/undo',

View File

@ -492,7 +492,7 @@ def sendFollowRequest(session,baseDir: str, \
newFollowJson = {
'@context': 'https://www.w3.org/ns/activitystreams',
'id': followActor+'#follows/'+followNickname,
'id': followActor+'/statuses/'+str(statusNumber),
'type': 'Follow',
'actor': followActor,
'object': followedId
@ -538,7 +538,7 @@ def sendFollowRequestViaServer(session,fromNickname: str,password: str,
statusNumber,published = getStatusNumber()
newFollowJson = {
'@context': 'https://www.w3.org/ns/activitystreams',
'id': followActor+'#follows/'+followNickname,
'id': followActor+'/statuses/'+str(statusNumber),
'type': 'Follow',
'actor': followActor,
'object': followedId
@ -612,14 +612,15 @@ def sendUnfollowRequestViaServer(session,fromNickname: str,password: str,
followActor=httpPrefix+'://'+fromDomainFull+'/users/'+fromNickname
followedId=httpPrefix+'://'+followDomainFull+'/users/'+followNickname
statusNumber,published = getStatusNumber()
unfollowJson = {
'@context': 'https://www.w3.org/ns/activitystreams',
'id': followActor+'#follows/'+followNickname+'/undo',
'id': followActor+'/statuses/'+str(statusNumber)+'/undo',
'type': 'Undo',
'actor': followActor,
'object': {
'id': followActor+'#follows/'+followNickname,
'id': followActor+'/statuses/'+str(statusNumber),
'type': 'Follow',
'actor': followActor,
'object': followedId

View File

@ -166,7 +166,12 @@ def validPublishedDate(published) -> bool:
return False
return True
def savePostToInboxQueue(baseDir: str,httpPrefix: str,nickname: str, domain: str,postJsonObject: {},messageBytes: str,httpHeaders: {},postPath: str,debug: bool) -> str:
def savePostToInboxQueue(baseDir: str,httpPrefix: str, \
nickname: str, domain: str, \
postJsonObject: {}, \
messageBytes: str, \
httpHeaders: {}, \
postPath: str,debug: bool) -> str:
"""Saves the give json to the inbox queue for the person
keyId specifies the actor sending the post
"""
@ -183,7 +188,9 @@ def savePostToInboxQueue(baseDir: str,httpPrefix: str,nickname: str, domain: str
actor=postJsonObject['actor']
postNickname=getNicknameFromActor(postJsonObject['actor'])
postDomain,postPort=getDomainFromActor(postJsonObject['actor'])
if isBlocked(baseDir,nickname,domain,postNickname,postDomain):
if isBlocked(baseDir,nickname,domain,postNickname,postDomain):
if debug:
print('DEBUG: post from '+postNickname+' blocked')
return None
if postPort:
if postPort!=80 and postPort!=443:
@ -195,6 +202,8 @@ def savePostToInboxQueue(baseDir: str,httpPrefix: str,nickname: str, domain: str
if postJsonObject['object'].get('content'):
if isinstance(postJsonObject['object']['content'], str):
if isFiltered(baseDir,nickname,domain,postJsonObject['object']['content']):
if debug:
print('DEBUG: post was filtered out due to content')
return None
originalPostId=None
if postJsonObject.get('id'):
@ -222,6 +231,7 @@ def savePostToInboxQueue(baseDir: str,httpPrefix: str,nickname: str, domain: str
destination=baseDir+'/accounts/'+handle+'/inbox/'+postId.replace('/','#')+'.json'
if os.path.isfile(destination):
if debug:
print(destination)
print('DEBUG: inbox item already exists')
return None
filename=inboxQueueDir+'/'+postId.replace('/','#')+'.json'
@ -480,8 +490,6 @@ def receiveUndoFollow(session,baseDir: str,httpPrefix: str, \
if debug:
print('DEBUG: actors do not match')
return False
if not messageJson['object'].get('to'):
messageJson['object']['to']=messageJson['object']['object']
nicknameFollower=getNicknameFromActor(messageJson['object']['actor'])
domainFollower,portFollower=getDomainFromActor(messageJson['object']['actor'])
@ -1342,7 +1350,7 @@ def runInboxQueue(projectVersion: str, \
maxReplies,allowDeletion)
else:
if debug:
print('DEBUG: object capabilities check failed')
print('DEBUG: object capabilities check has failed')
pprint(queueJson['post'])
else:
if not ocapAlways:
@ -1358,6 +1366,9 @@ def runInboxQueue(projectVersion: str, \
queueFilename,destination, \
maxReplies,allowDeletion)
if debug:
pprint(queueJson['post'])
print('No capability list within post')
print('ocapAlways: '+str(ocapAlways))
print('DEBUG: object capabilities check failed')
if debug:

View File

@ -104,7 +104,7 @@ def updateLikesCollection(postFilename: str,objectUrl: str, actor: str,debug: bo
postJsonObject['object']['likes']=likesJson
else:
if postJsonObject['object']['likes'].get('items'):
for likeItem in postJsonObject['likes']['items']:
for likeItem in postJsonObject['object']['likes']['items']:
if likeItem.get('actor'):
if likeItem['actor']==actor:
return

View File

@ -1245,6 +1245,46 @@ def sendSignedJson(postJsonObject: {},session,baseDir: str, \
thr.start()
return 0
def addToField(activityType: str,postJsonObject: {},debug: bool) -> ({},bool):
"""The Follow activity doesn't have a 'to' field and so one
needs to be added so that activity distribution happens in a consistent way
Returns true if a 'to' field exists or was added
"""
if postJsonObject.get('to'):
return postJsonObject,True
if debug:
pprint(postJsonObject)
print('DEBUG: no "to" field when sending to named addresses 2')
isSameType=False
toFieldAdded=False
if postJsonObject.get('object'):
if isinstance(postJsonObject['object'], str):
if postJsonObject.get('type'):
if postJsonObject['type']==activityType:
isSameType=True
if debug:
print('DEBUG: "to" field assigned to Follow')
postJsonObject['to']=[postJsonObject['object']]
toFieldAdded=True
elif isinstance(postJsonObject['object'], dict):
if postJsonObject['object'].get('type'):
if postJsonObject['object']['type']==activityType:
isSameType=True
if isinstance(postJsonObject['object']['object'], str):
if debug:
print('DEBUG: "to" field assigned to Follow')
postJsonObject['object']['to']=[postJsonObject['object']['object']]
postJsonObject['to']=[postJsonObject['object']['object']]
toFieldAdded=True
if not isSameType:
return postJsonObject,True
if toFieldAdded:
return postJsonObject,True
return postJsonObject,False
def sendToNamedAddresses(session,baseDir: str, \
nickname: str, domain: str, port: int, \
httpPrefix: str,federationList: [], \
@ -1261,16 +1301,29 @@ def sendToNamedAddresses(session,baseDir: str, \
return
if isinstance(postJsonObject['object'], dict):
if not postJsonObject['object'].get('to'):
return
if debug:
pprint(postJsonObject)
print('DEBUG: no "to" field when sending to named addresses')
if postJsonObject['object'].get('type'):
if postJsonObject['object']['type']=='Follow':
if isinstance(postJsonObject['object']['object'], str):
if debug:
print('DEBUG: "to" field assigned to Follow')
postJsonObject['object']['to']=[postJsonObject['object']['object']]
if not postJsonObject['object'].get('to'):
return
recipientsObject=postJsonObject['object']
else:
if not postJsonObject.get('to'):
postJsonObject,fieldAdded=addToField('Follow',postJsonObject,debug)
if not fieldAdded:
return
recipientsObject=postJsonObject
recipients=[]
recipientType=['to','cc']
for rType in recipientType:
if not recipientsObject.get(rType):
continue
for address in recipientsObject[rType]:
if address.endswith('#Public'):
continue

176
tests.py
View File

@ -484,7 +484,7 @@ def testPostMessageBetweenServers():
shutil.rmtree(aliceDir)
shutil.rmtree(bobDir)
def testFollowBetweenServers():
def testFollowBetweenServersOld():
print('Testing sending a follow request from one server to another')
global testServerAliceRunning
@ -768,6 +768,180 @@ def testFollowBetweenServers():
os.chdir(baseDir)
shutil.rmtree(baseDir+'/.tests')
def testFollowBetweenServers():
print('Testing sending a follow request from one server to another')
global testServerAliceRunning
global testServerBobRunning
global testServerEveRunning
testServerAliceRunning = False
testServerBobRunning = False
testServerEveRunning = False
httpPrefix='http'
useTor=False
federationList=[]
baseDir=os.getcwd()
if os.path.isdir(baseDir+'/.tests'):
shutil.rmtree(baseDir+'/.tests')
os.mkdir(baseDir+'/.tests')
ocapAlways=False
# create the servers
aliceDir=baseDir+'/.tests/alice'
aliceDomain='127.0.0.42'
alicePort=61935
thrAlice = \
threadWithTrace(target=createServerAlice, \
args=(aliceDir,aliceDomain,alicePort, \
federationList,False,False, \
ocapAlways),daemon=True)
bobDir=baseDir+'/.tests/bob'
bobDomain='127.0.0.64'
bobPort=61936
thrBob = \
threadWithTrace(target=createServerBob, \
args=(bobDir,bobDomain,bobPort, \
federationList,False,False, \
ocapAlways),daemon=True)
eveDir=baseDir+'/.tests/eve'
eveDomain='127.0.0.55'
evePort=61937
thrEve = \
threadWithTrace(target=createServerEve, \
args=(eveDir,eveDomain,evePort, \
federationList,False,False, \
False),daemon=True)
thrAlice.start()
thrBob.start()
thrEve.start()
assert thrAlice.isAlive()==True
assert thrBob.isAlive()==True
assert thrEve.isAlive()==True
# wait for all servers to be running
ctr=0
while not (testServerAliceRunning and testServerBobRunning and testServerEveRunning):
time.sleep(1)
ctr+=1
if ctr>60:
break
print('Alice online: '+str(testServerAliceRunning))
print('Bob online: '+str(testServerBobRunning))
print('Eve online: '+str(testServerEveRunning))
assert ctr<=60
time.sleep(1)
# In the beginning all was calm and there were no follows
print('*********************************************************')
print('Alice sends a follow request to Bob')
print('Both are strictly enforcing object capabilities')
os.chdir(aliceDir)
sessionAlice = createSession(aliceDomain,alicePort,useTor)
inReplyTo=None
inReplyToAtomUri=None
subject=None
aliceSendThreads = []
alicePostLog = []
followersOnly=False
saveToFile=True
clientToServer=False
ccUrl=None
alicePersonCache={}
aliceCachedWebfingers={}
aliceSendThreads=[]
alicePostLog=[]
sendResult = \
sendFollowRequest(sessionAlice,aliceDir, \
'alice',aliceDomain,alicePort,httpPrefix, \
'bob',bobDomain,bobPort,httpPrefix, \
clientToServer,federationList, \
aliceSendThreads,alicePostLog, \
aliceCachedWebfingers,alicePersonCache, \
True,__version__)
print('sendResult: '+str(sendResult))
bobCapsFilename=bobDir+'/accounts/bob@'+bobDomain+'/ocap/accept/'+httpPrefix+':##'+aliceDomain+':'+str(alicePort)+'#users#alice.json'
aliceCapsFilename=aliceDir+'/accounts/alice@'+aliceDomain+'/ocap/granted/'+httpPrefix+':##'+bobDomain+':'+str(bobPort)+'#users#bob.json'
for t in range(10):
if os.path.isfile(bobDir+'/accounts/bob@'+bobDomain+'/followers.txt'):
if os.path.isfile(aliceDir+'/accounts/alice@'+aliceDomain+'/following.txt'):
if os.path.isfile(bobCapsFilename):
if os.path.isfile(aliceCapsFilename):
break
time.sleep(1)
with open(bobCapsFilename, 'r') as fp:
bobCapsJson=commentjson.load(fp)
if not bobCapsJson.get('capability'):
print("Unexpected format for Bob's capabilities")
pprint(bobCapsJson)
assert False
assert validInbox(bobDir,'bob',bobDomain)
assert validInboxFilenames(bobDir,'bob',bobDomain,aliceDomain,alicePort)
print('\n\n*********************************************************')
print('Alice sends a message to Bob')
aliceSendThreads = []
alicePostLog = []
alicePersonCache={}
aliceCachedWebfingers={}
aliceSendThreads=[]
alicePostLog=[]
useBlurhash=False
sendResult = \
sendPost(__version__, \
sessionAlice,aliceDir,'alice', aliceDomain, alicePort, \
'bob', bobDomain, bobPort, ccUrl, \
httpPrefix, 'Alice message', followersOnly, saveToFile, \
clientToServer,None,None,useBlurhash, federationList, \
aliceSendThreads, alicePostLog, aliceCachedWebfingers, \
alicePersonCache,inReplyTo, inReplyToAtomUri, subject)
print('sendResult: '+str(sendResult))
queuePath=bobDir+'/accounts/bob@'+bobDomain+'/queue'
inboxPath=bobDir+'/accounts/bob@'+bobDomain+'/inbox'
aliceMessageArrived=False
for i in range(20):
time.sleep(1)
if os.path.isdir(inboxPath):
if len([name for name in os.listdir(inboxPath) if os.path.isfile(os.path.join(inboxPath, name))])>0:
aliceMessageArrived=True
print('Alice message sent to Bob!')
break
assert aliceMessageArrived==True
print('Message from Alice to Bob succeeded')
# stop the servers
thrAlice.kill()
thrAlice.join()
assert thrAlice.isAlive()==False
thrBob.kill()
thrBob.join()
assert thrBob.isAlive()==False
thrEve.kill()
thrEve.join()
assert thrEve.isAlive()==False
assert 'alice@'+aliceDomain in open(bobDir+'/accounts/bob@'+bobDomain+'/followers.txt').read()
assert 'bob@'+bobDomain in open(aliceDir+'/accounts/alice@'+aliceDomain+'/following.txt').read()
# queue item removed
assert len([name for name in os.listdir(queuePath) if os.path.isfile(os.path.join(queuePath, name))])==0
os.chdir(baseDir)
shutil.rmtree(baseDir+'/.tests')
def testFollowersOfPerson():
print('testFollowersOfPerson')
currDir=os.getcwd()