From 4efb5c9a30c12e0a98631f4991b807530a07a8a8 Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Fri, 30 Jul 2021 20:20:49 +0100 Subject: [PATCH] Start of unit test for groups --- epicyon.py | 2 + follow.py | 44 +++++++---- inbox.py | 3 + tests.py | 222 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 254 insertions(+), 17 deletions(-) diff --git a/epicyon.py b/epicyon.py index cb07e5c3f..5b9107789 100644 --- a/epicyon.py +++ b/epicyon.py @@ -54,6 +54,7 @@ from follow import clearFollows from follow import followerOfPerson from follow import sendFollowRequestViaServer from follow import sendUnfollowRequestViaServer +from tests import testGroupFollow from tests import testPostMessageBetweenServers from tests import testFollowBetweenServers from tests import testClientToServer @@ -608,6 +609,7 @@ if args.tests: sys.exit() if args.testsnetwork: print('Network Tests') + testGroupFollow() testPostMessageBetweenServers() testFollowBetweenServers() testClientToServer() diff --git a/follow.py b/follow.py index 69059d72a..5039d2df6 100644 --- a/follow.py +++ b/follow.py @@ -297,7 +297,7 @@ def unfollowerOfAccount(baseDir: str, nickname: str, domain: str, def clearFollows(baseDir: str, nickname: str, domain: str, - followFile='following.txt') -> None: + followFile: str = 'following.txt') -> None: """Removes all follows """ handle = nickname + '@' + domain @@ -452,10 +452,14 @@ def getFollowingFeed(baseDir: str, domain: str, port: int, path: str, if currPage == pageNumber: line2 = \ line.lower().replace('\n', '').replace('\r', '') - url = httpPrefix + '://' + \ - line2.split('@')[1] + \ - '/users/' + \ - line2.split('@')[0] + nick = line2.split('@')[0] + dom = line2.split('@')[1] + if not nick.startswith('!'): + # person actor + url = httpPrefix + '://' + dom + '/users/' + nick + else: + # group actor + url = httpPrefix + '://' + dom + '/c/' + nick following['orderedItems'].append(url) elif ((line.startswith('http') or line.startswith('hyper')) and @@ -563,16 +567,13 @@ def _storeFollowRequest(baseDir: str, if approveHandle in followersStr: alreadyFollowing = True - elif '://' + domainFull + '/profile/' + nickname in followersStr: - alreadyFollowing = True - elif '://' + domainFull + '/channel/' + nickname in followersStr: - alreadyFollowing = True - elif '://' + domainFull + '/accounts/' + nickname in followersStr: - alreadyFollowing = True - elif '://' + domainFull + '/u/' + nickname in followersStr: - alreadyFollowing = True - elif '://' + domainFull + '/c/' + nickname in followersStr: - alreadyFollowing = True + else: + usersPaths = getUserPaths() + for possibleUsersPath in usersPaths: + url = '://' + domainFull + possibleUsersPath + nickname + if url in followersStr: + alreadyFollowing = True + break if alreadyFollowing: if debug: @@ -754,13 +755,18 @@ def receiveFollowRequest(session, baseDir: str, httpPrefix: str, followersFilename + ' adding ' + approveHandle) if os.path.isfile(followersFilename): if approveHandle not in open(followersFilename).read(): + groupAccount = hasGroupPath(messageJson['object']) try: with open(followersFilename, 'r+') as followersFile: content = followersFile.read() if approveHandle + '\n' not in content: followersFile.seek(0, 0) - followersFile.write(approveHandle + '\n' + - content) + if not groupAccount: + followersFile.write(approveHandle + + '\n' + content) + else: + followersFile.write('!' + approveHandle + + '\n' + content) except Exception as e: print('WARN: ' + 'Failed to write entry to followers file ' + @@ -915,9 +921,13 @@ def sendFollowRequest(session, baseDir: str, statusNumber, published = getStatusNumber() + groupAccount = False if followNickname: followedId = followedActor followHandle = followNickname + '@' + requestDomain + groupAccount = hasGroupPath(followedActor) + if groupAccount: + followHandle = '!' + followHandle else: if debug: print('DEBUG: sendFollowRequest - assuming single user instance') diff --git a/inbox.py b/inbox.py index 4b98fa0b6..b3628e512 100644 --- a/inbox.py +++ b/inbox.py @@ -1945,6 +1945,8 @@ def _sendToGroupMembers(session, baseDir: str, handle: str, port: int, return if not postJsonObject.get('object'): return + if not hasObjectDict(postJsonObject): + return nickname = handle.split('@')[0] # groupname = _getGroupName(baseDir, handle) domain = handle.split('@')[1] @@ -1960,6 +1962,7 @@ def _sendToGroupMembers(session, baseDir: str, handle: str, port: int, senderStr = '@' + sendingActorNickname + '@' + sendingActorDomainFull contentStr = getBaseContentFromPost(postJsonObject, systemLanguage) if not contentStr.startswith(senderStr): + pprint(postJsonObject) postJsonObject['object']['content'] = \ senderStr + ' ' + contentStr postJsonObject['object']['contentMap'][systemLanguage] = \ diff --git a/tests.py b/tests.py index 25c351e1c..c3bed878d 100644 --- a/tests.py +++ b/tests.py @@ -69,6 +69,7 @@ from follow import unfollowAccount from follow import unfollowerOfAccount from follow import sendFollowRequest from person import createPerson +from person import createGroup from person import setDisplayNickname from person import setBio # from person import generateRSAKey @@ -136,9 +137,11 @@ from shares import createSharedItemFederationToken from shares import updateSharedItemFederationToken from shares import mergeSharedItemTokens +testServerGroupRunning = False testServerAliceRunning = False testServerBobRunning = False testServerEveRunning = False +thrGroup = None thrAlice = None thrBob = None thrEve = None @@ -773,6 +776,72 @@ def createServerEve(path: str, domain: str, port: int, federationList: [], sendThreads, False) +def createServerGroup(path: str, domain: str, port: int, + federationList: [], + hasFollows: bool, hasPosts: bool, + sendThreads: []): + print('Creating test server: Group on port ' + str(port)) + if os.path.isdir(path): + shutil.rmtree(path) + os.mkdir(path) + os.chdir(path) + sharedItemsFederatedDomains = [] + # systemLanguage = 'en' + nickname = 'testgroup' + httpPrefix = 'http' + proxyType = None + password = 'testgrouppass' + maxReplies = 64 + domainMaxPostsPerDay = 1000 + accountMaxPostsPerDay = 1000 + allowDeletion = True + privateKeyPem, publicKeyPem, person, wfEndpoint = \ + createGroup(path, nickname, domain, port, httpPrefix, True, + password) + deleteAllPosts(path, nickname, domain, 'inbox') + deleteAllPosts(path, nickname, domain, 'outbox') + global testServerGroupRunning + testServerGroupRunning = True + maxMentions = 10 + maxEmoji = 10 + onionDomain = None + i2pDomain = None + allowLocalNetworkAccess = True + maxNewswirePosts = 20 + dormantMonths = 3 + sendThreadsTimeoutMins = 30 + maxFollowers = 10 + verifyAllSignatures = True + brochMode = False + showNodeInfoAccounts = True + showNodeInfoVersion = True + city = 'London, England' + logLoginFailures = False + userAgentsBlocked = [] + print('Server running: Group') + runDaemon(sharedItemsFederatedDomains, + userAgentsBlocked, + logLoginFailures, city, + showNodeInfoAccounts, + showNodeInfoVersion, + brochMode, + verifyAllSignatures, + sendThreadsTimeoutMins, + dormantMonths, maxNewswirePosts, + allowLocalNetworkAccess, + 2048, False, True, False, False, True, maxFollowers, + 0, 100, 1024, 5, False, + 0, False, 1, False, False, False, + 5, True, True, 'en', __version__, + "instanceId", False, path, domain, + onionDomain, i2pDomain, None, port, port, + httpPrefix, federationList, maxMentions, maxEmoji, False, + proxyType, maxReplies, + domainMaxPostsPerDay, accountMaxPostsPerDay, + allowDeletion, True, True, False, sendThreads, + False) + + def testPostMessageBetweenServers(): print('Testing sending message from one server to the inbox of another') @@ -1246,6 +1315,158 @@ def testFollowBetweenServers(): shutil.rmtree(baseDir + '/.tests') +def testGroupFollow(): + print('Testing following of a group') + + global testServerAliceRunning + testServerAliceRunning = False + + # systemLanguage = 'en' + httpPrefix = 'http' + proxyType = None + federationList = [] + + baseDir = os.getcwd() + if os.path.isdir(baseDir + '/.tests'): + shutil.rmtree(baseDir + '/.tests') + os.mkdir(baseDir + '/.tests') + + # create the servers + aliceDir = baseDir + '/.tests/alice' + aliceDomain = '127.0.0.57' + alicePort = 61927 + aliceSendThreads = [] + # aliceAddress = aliceDomain + ':' + str(alicePort) + + testgroupDir = baseDir + '/.tests/testgroup' + testgroupDomain = '127.0.0.63' + testgroupPort = 61925 + testgroupSendThreads = [] + testgroupAddress = testgroupDomain + ':' + str(testgroupPort) + + global thrAlice + if thrAlice: + while thrAlice.is_alive(): + thrAlice.stop() + time.sleep(1) + thrAlice.kill() + + thrAlice = \ + threadWithTrace(target=createServerAlice, + args=(aliceDir, aliceDomain, alicePort, + testgroupAddress, + federationList, False, False, + aliceSendThreads), + daemon=True) + + global thrGroup + if thrGroup: + while thrGroup.is_alive(): + thrGroup.stop() + time.sleep(1) + thrGroup.kill() + + thrGroup = \ + threadWithTrace(target=createServerGroup, + args=(testgroupDir, testgroupDomain, testgroupPort, + federationList, False, False, + testgroupSendThreads), + daemon=True) + + thrAlice.start() + thrGroup.start() + assert thrAlice.is_alive() is True + assert thrGroup.is_alive() is True + + # wait for all servers to be running + ctr = 0 + while not (testServerAliceRunning and testServerGroupRunning): + time.sleep(1) + ctr += 1 + if ctr > 60: + break + print('Alice online: ' + str(testServerAliceRunning)) + print('Test Group online: ' + str(testServerGroupRunning)) + assert ctr <= 60 + time.sleep(1) + + queuePath = \ + testgroupDir + '/accounts/testgroup@' + testgroupDomain + '/queue' + + # In the beginning the test group had no followers + + print('*********************************************************') + print('Alice sends a follow request to the test group') + os.chdir(aliceDir) + sessionAlice = createSession(proxyType) + # inReplyTo = None + # inReplyToAtomUri = None + # subject = None + alicePostLog = [] + # followersOnly = False + # saveToFile = True + clientToServer = False + # ccUrl = None + alicePersonCache = {} + aliceCachedWebfingers = {} + alicePostLog = [] + testgroupActor = httpPrefix + '://' + testgroupAddress + '/users/testgroup' + sendResult = \ + sendFollowRequest(sessionAlice, aliceDir, + 'alice', aliceDomain, alicePort, httpPrefix, + 'testgroup', testgroupDomain, testgroupActor, + testgroupPort, httpPrefix, + clientToServer, federationList, + aliceSendThreads, alicePostLog, + aliceCachedWebfingers, alicePersonCache, + True, __version__) + print('sendResult: ' + str(sendResult)) + + for t in range(16): + if os.path.isfile(testgroupDir + '/accounts/testgroup@' + + testgroupDomain + '/followers.txt'): + if os.path.isfile(aliceDir + '/accounts/alice@' + + aliceDomain + '/following.txt'): + if os.path.isfile(aliceDir + '/accounts/alice@' + + aliceDomain + '/followingCalendar.txt'): + break + time.sleep(1) + + assert validInbox(testgroupDir, 'testgroup', testgroupDomain) + assert validInboxFilenames(testgroupDir, 'testgroup', testgroupDomain, + aliceDomain, alicePort) + assert 'alice@' + aliceDomain in open(testgroupDir + + '/accounts/testgroup@' + + testgroupDomain + + '/followers.txt').read() + assert 'testgroup@' + testgroupDomain in open(aliceDir + + '/accounts/alice@' + + aliceDomain + + '/following.txt').read() + testgroupHandle = 'testgroup@' + testgroupDomain + assert testgroupHandle in open(aliceDir + + '/accounts/alice@' + + aliceDomain + + '/followingCalendar.txt').read() + + # stop the servers + thrAlice.kill() + thrAlice.join() + assert thrAlice.is_alive() is False + + thrGroup.kill() + thrGroup.join() + assert thrGroup.is_alive() is False + + # queue item removed + time.sleep(4) + 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() @@ -3285,6 +3506,7 @@ def _testFunctions(): 'getThisWeeksEvents', 'getAvailability', '_testThreadsFunction', + 'createServerGroup', 'createServerAlice', 'createServerBob', 'createServerEve',