def test_check_post(self): """ Will test that check_post returns the correct value with various combinations. Note: Bare with this one it is quite tedious. """ # Create two test users user1 = create_account('user1', '*****@*****.**', 'Password') user2 = create_account('user2', '*****@*****.**', 'Password') # Create a post post1 = create_post(user1, 'user1', 'Test post') # check_post should be True when user 1 creates post 1 self.assertTrue(check_post(user1, post1)) # check_post should be false, user 2 didn't create post 1 self.assertFalse(check_post(user2, post1)) # Create a couple of comments comment1 = create_post(user1, 'user1', 'Test comment', post1) comment2 = create_post(user2, 'user2', 'Test comment', post1) # Ensure the check_post is fine for all self.assertTrue(check_post(user1, post1, comment1)) # This does not look correct but is. See backend.py@check_post self.assertTrue(check_post(user1, post1, comment1)) # Ensure the function isn't broken on comments self.assertFalse(check_post(user2, post1, comment1)) self.assertFalse(check_post(user1, K.NIL_VALUE, comment1)) self.assertFalse(check_post(user2, K.NIL_VALUE, comment2))
def test_advanced_search(self): """Cover using the `@` and `#` modifiers to limit the search type. """ user1 = create_account('user1', '*****@*****.**', 'Password') user2 = create_account('user2', '*****@*****.**', 'Password') create_post(user1, 'user1', '#pjuu #user2') create_post(user2, 'user2', '#pjuu #user1') for i in range(1, 101): create_post(user1, 'user1', '#pagination{}'.format(i)) # Try come basic search terms self.assertEqual(search('user').total, 4) self.assertEqual(search('user1').total, 2) self.assertEqual(search('user2').total, 2) self.assertEqual(search('pjuu').total, 2) # Users only self.assertEqual(search('@user').total, 2) self.assertEqual(search('@user1').total, 1) # erroneous spacing doesn't matter self.assertEqual(search('@ us').total, 2) # Posts only self.assertEqual(search('#user').total, 2) self.assertEqual(search('#user1').total, 1) self.assertEqual(search('#pjuu').total, 2) # Test pagination in search self.assertEqual(len(search('#pagination', 1, 50).items), 50) self.assertEqual(len(search('#pagination', 2, 50).items), 50)
def test_get_feed(self): """ Attempt to get a users feed under certain circumstances. """ # Get test user user1 = create_account('user1', '*****@*****.**', 'Password') # Ensure an empty feed is returned. Remember these are paginations self.assertEqual(len(get_feed(user1).items), 0) # Ensure a users own post is added to thier feed post1 = create_post(user1, 'user1', 'Test post') # Ensure the list is the correct length self.assertEqual(len(get_feed(user1).items), 1) self.assertEqual(get_feed(user1).total, 1) # Ensure the item is in Redis self.assertIn(post1, r.zrange(K.USER_FEED.format(user1), 0, -1)) # Create a second user, make 1 follow them, make then post and ensure # that the new users post appears in user 1s feed user2 = create_account('user2', '*****@*****.**', 'Password') follow_user(user1, user2) post2 = create_post(user2, 'user2', 'Test post') # Check user 1's feed for the next item self.assertEqual(len(get_feed(user1).items), 2) self.assertEqual(get_feed(user1).total, 2) # Ensure the item is in Redis self.assertIn(post2, r.zrange(K.USER_FEED.format(user1), 0, -1)) # Delete user 2 and ensure user 1's feed cleans itself delete_account(user2) self.assertEqual(len(get_feed(user1).items), 1) self.assertEqual(get_feed(user1).total, 1) # Ensure the item is not in Redis self.assertNotIn(post2, r.zrange(K.USER_FEED.format(user1), 0, -1))
def test_search(self): """Make sure users can actually find things on the site.""" # Create test user user1 = create_account('user1', '*****@*****.**', 'Password') # Ensure that the user can be found self.assertEqual(len(search('user1').items), 1) self.assertEqual(search('user1').total, 1) # Ensure partial match self.assertEqual(len(search('use').items), 1) self.assertEqual(search('use').total, 1) # Ensure nothing return if no user self.assertEqual(len(search('user2').items), 0) self.assertEqual(search('user2').total, 0) # Ensure no partial if incorrect self.assertEqual(len(search('bob').items), 0) self.assertEqual(search('bob').total, 0) # Create a second test user and a post with a hashtag and # ensure both show in the results. user2 = create_account('user2', '*****@*****.**', 'Password') # Create the post as user1 as we are going to delete user2 create_post(user1, 'user1', '#user2') # Ensure the new user can be found self.assertEqual(len(search('user2').items), 2) self.assertEqual(search('user2').total, 2) # Ensure partial match returns both test1/2 users self.assertEqual(len(search('use').items), 3) self.assertEqual(search('use').total, 3) # Delete the account user2 and try searching again # Only the hashtag should show delete_account(user2) self.assertEqual(search('user2').total, 1)
def test_surrounding_characters(self): """Can parse objects be in parenthesis""" create_account('user1', '*****@*****.**', 'Password1') links, mentions, hashtags = parse_post('(@user1), (pjuu.com), (#hash)') self.assertEqual(links[0]['link'], 'http://pjuu.com') self.assertEqual(mentions[0]['username'], 'user1') self.assertEqual(hashtags[0]['hashtag'], 'hash')
def test_delete_account_followers_following(self): """Does the users social graph go on deletion of account? """ user1 = create_account('user1', '*****@*****.**', 'Password') user2 = create_account('user2', '*****@*****.**', 'Password') # Friends :) self.assertTrue(follow_user(user1, user2)) self.assertTrue(follow_user(user2, user1)) # Ensure Redis's sorted sets are correct self.assertIn(user2, r.zrange(K.USER_FOLLOWERS.format(user1), 0, -1)) self.assertIn(user2, r.zrange(K.USER_FOLLOWING.format(user1), 0, -1)) self.assertIn(user1, r.zrange(K.USER_FOLLOWERS.format(user2), 0, -1)) self.assertIn(user1, r.zrange(K.USER_FOLLOWING.format(user2), 0, -1)) delete_account(user1) # Ensure sorted sets are emptied self.assertNotIn(user2, r.zrange(K.USER_FOLLOWERS.format(user1), 0, -1)) self.assertNotIn(user2, r.zrange(K.USER_FOLLOWING.format(user1), 0, -1)) self.assertNotIn(user1, r.zrange(K.USER_FOLLOWERS.format(user2), 0, -1)) self.assertNotIn(user1, r.zrange(K.USER_FOLLOWING.format(user2), 0, -1))
def test_delete_account_posts_replies(self): """Do all posts and replies get removed on deletion of account? """ user1 = create_account('user1', '*****@*****.**', 'Password') user2 = create_account('user2', '*****@*****.**', 'Password') post1 = create_post(user1, 'user1', 'Test post') post2 = create_post(user2, 'user2', 'Test post') # Create multiple comments on both posts comment1 = create_post(user1, 'user1', "Test comment", post1) create_post(user1, 'user1', "Test comment", post1) create_post(user1, 'user1', "Test comment", post1) create_post(user1, 'user1', "Test comment", post2) delete_account(user1) # All posts created by user1 and the replies on those post, gone? self.assertIsNone(m.db.posts.find_one({'_id': post1})) self.assertIsNone(m.db.posts.find_one({'reply_to': post1})) # Ensure the reply is gone self.assertIsNone(m.db.posts.find_one({'_id': comment1})) # Is feed empty? self.assertFalse(r.lrange(K.USER_FEED.format(user1), 0, -1))
def test_search(self): """ Make sure users can actually find each other. This will need a lot more work once we add in a proper search facility rather than just the Redis KEYS command """ # Create test user create_account('user1', '*****@*****.**', 'Password') # Ensure that the user can be found self.assertEqual(len(search('user1').items), 1) self.assertEqual(search('user1').total, 1) # Ensure partial match self.assertEqual(len(search('use').items), 1) self.assertEqual(search('use').total, 1) # Ensure nothing return if no user self.assertEqual(len(search('user2').items), 0) self.assertEqual(search('user2').total, 0) # Ensure no partial if incorrect self.assertEqual(len(search('bob').items), 0) self.assertEqual(search('bob').total, 0) # Create a second test user user2 = create_account('user2', '*****@*****.**', 'Password') # Ensure the new user can be found self.assertEqual(len(search('user2').items), 1) self.assertEqual(search('user2').total, 1) # Ensure partial match returns both test1/2 users self.assertEqual(len(search('use').items), 2) self.assertEqual(search('use').total, 2) # Delete the account test 2 and try searching again # Adding in this test as it has stung us before delete_account(user2) self.assertEqual(search('test2').total, 0)
def test_back_feed(self): """Test the back feed feature, once a user follows another user it places their latest 5 posts on their feed. They will be in chronologic order. I know that ``back_feed()`` is a posts feature but it is triggered on follow. """ user1 = create_account('user1', '*****@*****.**', 'Password') user2 = create_account('user2', '*****@*****.**', 'Password') # Create 6 test posts ('Test 1' shouldn't be back fed) post1 = create_post(user1, 'user1', 'Test 1') post2 = create_post(user1, 'user1', 'Test 2') post3 = create_post(user1, 'user1', 'Test 3') post4 = create_post(user1, 'user1', 'Test 4') post5 = create_post(user1, 'user1', 'Test 5') post6 = create_post(user1, 'user1', 'Test 6') follow_user(user2, user1) # Check that the posts are in the feed (we can do this in Redis) feed = r.zrevrange(k.USER_FEED.format(user2), 0, -1) self.assertNotIn(post1, feed) self.assertIn(post2, feed) self.assertIn(post3, feed) self.assertIn(post4, feed) self.assertIn(post5, feed) self.assertIn(post6, feed)
def test_unicode_character(self): """Do unicode characters break things.""" create_account('user1', '*****@*****.**', 'Password1') links, mentions, hashtags = parse_post('၍ @user1, ☂pjuu.com, 㒅 #hash') self.assertEqual(links[0]['link'], 'http://pjuu.com') self.assertEqual(mentions[0]['username'], 'user1') self.assertEqual(hashtags[0]['hashtag'], 'hash')
def test_alerts(self): """ Unlike the test_alerts() definition in the users package this just tests that TaggingAlert and CommentingAlert are generated in the right situation """ # Create 3 test users user1 = create_account('user1', '*****@*****.**', 'Password') user2 = create_account('user2', '*****@*****.**', 'Password') user3 = create_account('user3', '*****@*****.**', 'Password') # No need to activate the accounts activate(user1) activate(user2) activate(user3) # User1 tag user2 in a post post1 = create_post(user1, 'user1', 'Hello @user2') # Get alerts for test2 and check that it is correct alert = get_alerts(user2).items[0] self.assertTrue(isinstance(alert, TaggingAlert)) self.assertEqual(alert.user['username'], 'user1') self.assertEqual(alert.user['email'], '*****@*****.**') self.assertIn('tagged you in a', alert.prettify()) # Have user2 comment on a the post and check that user1 has the alert create_post(user2, 'user2', 'Hello', post1) # User 1 should now have a commenting alert from user2 alert = get_alerts(user1).items[0] self.assertTrue(isinstance(alert, CommentingAlert)) self.assertEqual(alert.user['username'], 'user2') self.assertEqual(alert.user['email'], '*****@*****.**') # Please remember that prettify requires a uid to format it to self.assertIn('commented on a', alert.prettify(user1)) self.assertIn('you posted', alert.prettify(user1)) # Create a comment as user3 so they become subscribed create_post(user3, 'user3', 'Hello', post1) # Check that if user1 posts a comment user2 get a tagging alert create_post(user1, 'user1', 'Hello', post1) # Check alerts for user2 alert = get_alerts(user2).items[0] self.assertTrue(isinstance(alert, CommentingAlert)) self.assertIn('you were tagged in', alert.prettify(user2)) # Check alerts for user3 alert = get_alerts(user3).items[0] self.assertTrue(isinstance(alert, CommentingAlert)) self.assertIn('you commented on', alert.prettify(user3)) # To check that an invalid subscription reason returns the generic # reason. This should not happen on the site. # Manually change the score in Redis to a high number r.zincrby(K.POST_SUBSCRIBERS.format(post1), user3, 100) # Check the new prettify message alert = get_alerts(user3).items[0] self.assertTrue(isinstance(alert, CommentingAlert)) self.assertIn('you are subscribed to', alert.prettify(user3))
def test_create_reply(self): """Test that a reply can be made on a post """ user1 = create_account('user1', '*****@*****.**', 'Password') # Create a second test user to test commenting on someone else post user2 = create_account('user2', '*****@*****.**', 'Password') # Create post post1 = create_post(user1, 'user1', 'Test post') # Create comment reply1 = create_post(user1, 'user1', 'Test comment', post1) # Check the comment was created self.assertIsNotNone(get_post(reply1)) # Create a comment by the second user reply2 = create_post(user2, 'user1', 'Test comment', post1) # Check the comment was created self.assertIsNotNone(get_post(reply2)) # Check the comment hash has the data we expect, we will do this with # comment1 comment = get_post(reply1) self.assertIsNotNone(comment) self.assertEqual(comment.get('_id'), reply1) self.assertEqual(comment.get('user_id'), user1) self.assertEqual(comment.get('reply_to'), post1) self.assertEqual(comment.get('body'), 'Test comment') self.assertEqual(comment.get('score'), 0) self.assertIsNotNone(comment.get('created')) self.assertNotIn('upload', comment) # Create a post with an image image = io.BytesIO(open('tests/upload_test_files/otter.jpg').read()) reply1 = create_post(user1, 'user1', 'Test post #2', reply_to=post1, upload=image) self.assertIsNotNone(reply1) comment = get_post(reply1) self.assertIn('upload', comment) self.assertIsNotNone(comment.get('upload')) # Create a post with a broken image, ensure it's handled correctly image = io.BytesIO() reply2 = create_post(user1, 'user1', 'Test post #3', reply_to=post1, upload=image) self.assertIsNone(reply2) comment = get_post(reply2) self.assertIsNone(comment)
def test_flag_control(self): """Ensure flagged posts appear in the dashboard""" user1 = create_account('user1', '*****@*****.**', 'Password') user2 = create_account('user2', '*****@*****.**', 'Password') # Make user1 OP bite(user1) activate(user1) post1 = create_post(user2, 'user2', 'post1') post2 = create_post(user2, 'user2', 'post2') comment1 = create_post(user2, 'user2', 'comment1', post1) comment2 = create_post(user2, 'user2', 'comment2', post1) # Flag all the posts flag_post(user1, post1) flag_post(user1, post2) flag_post(user1, comment1) flag_post(user1, comment2) self.client.post(url_for('auth.signin'), data={ 'username': '******', 'password': '******' }) resp = self.client.get(url_for('dashboard.dashboard')) s = '{0} - <a href="{1}">{2}</a>: <a href="{3}">{4}</a> ' + \ '[<a href="{5}">Unflag</a>]' self.assertIn(s.format( 1, url_for('users.profile', username='******'), 'user2', url_for('posts.view_post', username='******', post_id=post1), post1, url_for('posts.unflag_post', post_id=post1) ), resp.data) self.assertIn(s.format( 1, url_for('users.profile', username='******'), 'user2', url_for('posts.view_post', username='******', post_id=post1), comment1, url_for('posts.unflag_post', post_id=comment1) ) + ' (comment)', resp.data)
def test_remove_from_feed(self): user1 = create_account('user1', '*****@*****.**', 'Password') user2 = create_account('user2', '*****@*****.**', 'Password') # Activate activate(user1) follow_user(user1, user2) post = create_post(user2, 'user2', 'User 2, is here') # Check that the post appears in the users feed resp = self.client.post(url_for('auth.signin'), data={ 'username': '******', 'password': '******' }, follow_redirects=True) self.assertIn('User 2, is here', resp.data) self.assertIn('remove:post:{}'.format(post), resp.data) # Hide the post resp = self.client.post(url_for('users.remove_from_feed', post_id=post), follow_redirects=True) self.assertNotIn('User 2, is here', resp.data) self.assertNotIn('remove:post:{}'.format(post), resp.data) self.assertIn('Message has been removed from feed', resp.data) # Can a user remove their own post? post = create_post(user1, 'user1', 'User 1, is here') # The user should not see a hide button though resp = self.client.get(url_for('users.feed')) self.assertIn('User 1, is here', resp.data) self.assertNotIn('remove:post:{}'.format(post), resp.data) # Ensure the URL hides the post resp = self.client.post(url_for('users.remove_from_feed', post_id=post), follow_redirects=True) self.assertNotIn('User 1, is here', resp.data) self.assertIn('Message has been removed from feed', resp.data) # Ensure removing a post that is not in your feed does not displau a # flash message resp = self.client.post(url_for('users.remove_from_feed', post_id=''), follow_redirects=True) self.assertNotIn('Message has been removed from feed', resp.data)
def test_postify(self): """Test that postify renders posts correctly when the correct informations is attached. .. note: This is not intended to test the parsing but simply that what is parsed is rendered correctly. """ # We need a user to post as. user1 = create_account('user1', '*****@*****.**', 'Password') activate(user1) self.client.post(url_for('auth.signin'), data={ 'username': '******', 'password': '******' }) # Create a post with a user that does not exist there should be no # rendering involved resp = self.client.post(url_for('posts.post'), data={ 'body': 'Hello @joe' }, follow_redirects=True) self.assertIn('Hello @joe', resp.data) # Create another user and then tag them user2 = create_account('user2', '*****@*****.**', 'Password') activate(user2) resp = self.client.post(url_for('posts.post'), data={ 'body': 'Hello @user2' }, follow_redirects=True) self.assertIn('Hello <a href="{0}">@user2</a>'.format( url_for('users.profile', username='******')), resp.data) # Check a link resp = self.client.post(url_for('posts.post'), data={ 'body': 'Visit https://pjuu.com' }, follow_redirects=True) self.assertIn('Visit <a href="https://pjuu.com" target="_blank">' 'https://pjuu.com</a>', resp.data) # Test a hashtag resp = self.client.post(url_for('posts.post'), data={ 'body': 'Wow #hashtag' }, follow_redirects=True) self.assertIn('Wow <a href="{0}">#hashtag</a>'.format( url_for('posts.hashtags', hashtag='hashtag')), resp.data)
def test_alertmanager(self): """ Test the alert manager. Similar to the above a very simple test. Will check that it can alert users and one can be created. """ # Create our alert manager am = AlertManager() # Try and load a non-existant alert self.assertIsNone(am.get(k.NIL_VALUE)) # Try and alert on something which is not an alert self.assertRaises(ValueError, lambda: am.alert('ALERT', k.NIL_VALUE)) # Test that alerting a single users does not work, they need to be # iterable # Create an alert alert = BaseAlert(k.NIL_VALUE) self.assertRaises(TypeError, lambda: am.alert(alert, 1)) # Create a couple of users user1 = create_account('user1', '*****@*****.**', 'Password') user2 = create_account('user2', '*****@*****.**', 'Password') # Ensure the length of user1's alert feed is 0 self.assertEqual(r.zcard(k.USER_ALERTS.format(user1)), 0) # Create an alert from user2 alert = BaseAlert(user2) # Alert user1 am.alert(alert, [user1]) # Ensure the length of user1's alert feed is 1 self.assertEqual(r.zcard(k.USER_ALERTS.format(user1)), 1) # Get alerts for user1, user Redis directly alerts = r.zrange(k.USER_ALERTS.format(user1), 0, 0) # Get the alert from alerts alert = am.get(alerts[0]) self.assertIsNotNone(alert) self.assertEqual(alert.user.get('username'), 'user2') self.assertEqual(alert.user.get('email'), '*****@*****.**') # Delete test2 and ensure getting the alert returns None delete_account(user2) alert = am.get(alerts[0]) self.assertIsNone(alert)
def test_approved_feed_population(self): """Ensure only approved users get approved posts but in there feed.""" # Create a user to test creating post user1 = create_account('user1', '*****@*****.**', 'Password') user2 = create_account('user2', '*****@*****.**', 'Password') user3 = create_account('user3', '*****@*****.**', 'Password') follow_user(user2, user1) follow_user(user3, user1) approve_user(user1, user2) create_post(user1, 'user1', 'Test post', permission=K.PERM_APPROVED) self.assertEqual(len(get_feed(user2).items), 1) self.assertEqual(len(get_feed(user3).items), 0)
def test_session_fixation(self): """Ensure if session is empty that a new session is given.""" user1 = create_account('user1', '*****@*****.**', 'Password') activate(user1) resp = self.client.post(url_for('auth.signin'), data={ 'username': '******', 'password': '******' }) session_id = None for header in resp.headers: if header[0] == 'Set-Cookie': session_id = parse_cookie(header[1])['session'] rs.delete(session_id) resp = self.client.post(url_for('auth.signin'), data={ 'username': '******', 'password': '******' }) # Find the Set-Cookie header so we can parse it and check the session # identifier has been updated for header in resp.headers: if header[0] == 'Set-Cookie': self.assertNotEqual(session_id, parse_cookie(header[1])['session'])
def test_get_upload(self): """Tests the simple wrapper around ``lib.uploads.get_upload`` """ user1 = create_account('user1', '*****@*****.**', 'Password') activate(user1) # Create the post with an upload to get image = io.BytesIO(open('tests/upload_test_files/otter.jpg').read()) post1 = create_post(user1, 'user1', 'Test post', upload=image) self.assertIsNotNone(post1) post = get_post(post1) # Try and get the post and ensure we are redirected because we are not # logged in resp = self.client.get(url_for('posts.get_upload', filename=post.get('upload'))) self.assertEqual(resp.status_code, 302) # Log in as user1 and get the upload resp = self.client.post(url_for('auth.signin'), data={ 'username': '******', 'password': '******' }, follow_redirects=True) self.assertEqual(resp.status_code, 200) resp = self.client.get(url_for('posts.get_upload', filename=post.get('upload'))) self.assertEqual(resp.status_code, 200) self.assertEqual(resp.headers['Content-Type'], 'image/png')
def test_get_posts(self): """ Test users post list works correctly """ # Create test user user1 = create_account('user1', '*****@*****.**', 'Password') # Ensure the users post list is empty self.assertEqual(len(get_posts(user1).items), 0) # Create a few test posts, ensure they appears in the users list post1 = create_post(user1, 'user1', 'Test post 1') post2 = create_post(user1, 'user1', 'Test post 2') create_post(user1, 'user1', 'Test post 3') self.assertEqual(len(get_posts(user1).items), 3) self.assertEqual(get_posts(user1).total, 3) # Delete one of the posts and ensure that it does not appear in the # list. delete_post(post1) # Ensure the above is now correct with post1 missing self.assertEqual(len(get_posts(user1).items), 2) self.assertEqual(get_posts(user1).total, 2) # Delete a post from MongoDB with the driver m.db.posts.remove({'_id': post2}) # Ensure the above is now correct with post2 missing self.assertEqual(len(get_posts(user1).items), 1) self.assertEqual(get_posts(user1).total, 1)
def signup(): """ """ form = SignUpForm(request.form) if request.method == 'POST': if form.validate(): # User successfully signed up, create an account uid = create_account(form.username.data, form.email.data, form.password.data) # Lets check the account was created # This would only fail in the event of a race condition if uid: # pragma: no branch token = generate_token({'action': 'activate', 'uid': uid}) # Send an e-mail to activate their account send_mail('Pjuu Account Notification - Activation', [form.email.data], text_body=render_template('emails/activate.txt', token=token), html_body=render_template('emails/activate.html', token=token)) flash( 'Yay! You\'ve signed up<br/>' 'We\'ve sent an e-mail to {}<br/>' 'Please activate your account'.format(form.email.data), 'success') return redirect(url_for('auth.signin')) flash('Oh no! There are errors in your form. Please try again.', 'error') return render_template('signup.html', form=form)
def test_avatars_hashtag_search(self): """Ensure user avatars appear when searching for posts with a hashtag """ user1 = create_account('user1', '*****@*****.**', 'Password') # Activate it activate(user1) # Signin self.client.post(url_for('auth.signin'), data={ 'username': '******', 'password': '******' }) # Ensure user avatar appear in the search when searching for hashtags image = io.BytesIO(open('tests/upload_test_files/otter.jpg').read()) self.client.post(url_for('users.settings_profile'), data={'upload': (image, 'otter.png')}, follow_redirects=True) # Get the user so we can see if the avatar is appearing user = get_user(user1) # Create a post to search for post1 = create_post(user1, 'user1', 'Hello #pjuuie\'s') resp = self.client.get(url_for('users.search', query='#pjuuie')) self.assertIn('<!-- list:post:%s -->' % post1, resp.data) self.assertIn(url_for('posts.get_upload', filename=user.get('avatar')), resp.data)
def test_logged_in(self): """Check the pages work when logged in """ # Let's create a user an login user1 = create_account('user1', '*****@*****.**', 'Password') # Activate the account self.assertTrue(activate(user1)) # Log the user in resp = self.client.post(url_for('auth.signin'), data={ 'username': '******', 'password': '******' }, follow_redirects=True) # About resp = self.client.get(url_for('pages.about')) self.assertEqual(resp.status_code, 200) self.assertIn('<!-- menu: logged in -->', resp.data) self.assertIn('<h1>About Us</h1>', resp.data) # Terms resp = self.client.get(url_for('pages.terms')) self.assertEqual(resp.status_code, 200) self.assertIn('<!-- menu: logged in -->', resp.data) self.assertIn('<h1>Terms of Service</h1>', resp.data) # Privacy resp = self.client.get(url_for('pages.privacy')) self.assertEqual(resp.status_code, 200) self.assertIn('<!-- menu: logged in -->', resp.data) self.assertIn('<h1>Privacy</h1>', resp.data)
def test_authenticate(self): """Can a user be authenticated? """ user1 = create_account('user1', '*****@*****.**', 'Password') self.assertIsNotNone(user1) # Check authenticate self.assertEqual(authenticate('user1', 'Password').get('_id'), user1) # Check auth with e-mail self.assertEqual(authenticate('*****@*****.**', 'Password').get('_id'), user1) # Case in-sensitive test self.assertEqual(authenticate('USER1', 'Password').get('_id'), user1) self.assertEqual(authenticate('*****@*****.**', 'Password').get('_id'), user1) # Ensure case in-sensitive password does NOT WORK self.assertIsNone(authenticate('user1', 'password')) self.assertIsNone(authenticate('user1', 'PASSWORD')) # Check incorrect password self.assertIsNone(authenticate('user1', 'Pass')) # Check non-existent user self.assertIsNone(authenticate('userX', 'Password')) # Check no glob username self.assertIsNone(authenticate('use*', 'Password')) # Check no glob password (just to be safe) self.assertIsNone(authenticate('user1', 'Passw*'))
def test_basealert(self): """Simple test for alerts. Ensure that they do what we want them too do out of the box. Ensure user() works. Also check that the AlertManager can't be broken. """ # Check that an alert will not work with a non-existant get_user alert = BaseAlert(k.NIL_VALUE) # Check that there is a timestamp self.assertGreater(alert.timestamp, 0) # We should get nothing back for alerts when it comes to our # existant user self.assertIsNone(alert.user) # Check that the alert does NOT verify self.assertFalse(alert.verify()) # Use lambda to test the exception comes out. # Alerts based on BaseAlert _SHOULD_ implement these themselves self.assertRaises(NotImplementedError, lambda: alert.prettify()) # Create a user an check that at least get_username and get_email work user1 = create_account('user1', '*****@*****.**', 'Password') alert = BaseAlert(user1) self.assertEqual(alert.user.get('username'), 'user1') self.assertEqual(alert.user.get('email'), '*****@*****.**') self.assertTrue(alert.verify())
def test_get_feed_pagination_sizes(self): """Ensure that getting the feed at different pagination sizes work""" user1 = create_account('user1', '*****@*****.**', 'Password') user2 = create_account('user2', '*****@*****.**', 'Password') follow_user(user1, user2) # Create lots of posts so they apear in user1's feed. for i in xrange(101): create_post(user2, 'user2', 'Post {}'.format(i)) FEED_ITEMS_PER_PAGE = app.config.get('FEED_ITEMS_PER_PAGE') self.assertEqual(len(get_feed(user1).items), FEED_ITEMS_PER_PAGE) self.assertEqual(len(get_feed(user1, per_page=25).items), 25) self.assertEqual(len(get_feed(user1, per_page=50).items), 50) self.assertEqual(len(get_feed(user1, per_page=100).items), 100)
def signup(): """ """ form = SignUpForm(request.form) if request.method == 'POST': if form.validate(): # User successfully signed up, create an account uid = create_account(form.username.data, form.email.data, form.password.data) # Lets check the account was created # This would only fail in the event of a race condition if uid: # pragma: no branch token = generate_token({'action': 'activate', 'uid': uid}) # Send an e-mail to activate their account send_mail( 'Pjuu Account Notification - Activation', [form.email.data], text_body=render_template('emails/activate.txt', token=token), html_body=render_template('emails/activate.html', token=token) ) flash('Yay! You\'ve signed up<br/>' 'We\'ve sent an e-mail to {}<br/>' 'Please activate your account'.format(form.email.data), 'success') return redirect(url_for('auth.signin')) flash('Oh no! There are errors in your form. Please try again.', 'error') return render_template('signup.html', form=form)
def test_authenticate(self): """Can a user be authenticated? """ user1 = create_account('user1', '*****@*****.**', 'Password') self.assertIsNotNone(user1) # Check authenticate self.assertEqual(authenticate('user1', 'Password').get('_id'), user1) # Check auth with e-mail self.assertEqual( authenticate('*****@*****.**', 'Password').get('_id'), user1) # Case in-sensitive test self.assertEqual(authenticate('USER1', 'Password').get('_id'), user1) self.assertEqual( authenticate('*****@*****.**', 'Password').get('_id'), user1) # Ensure case in-sensitive password does NOT WORK self.assertIsNone(authenticate('user1', 'password')) self.assertIsNone(authenticate('user1', 'PASSWORD')) # Check incorrect password self.assertIsNone(authenticate('user1', 'Pass')) # Check non-existent user self.assertIsNone(authenticate('userX', 'Password')) # Check no glob username self.assertIsNone(authenticate('use*', 'Password')) # Check no glob password (just to be safe) self.assertIsNone(authenticate('user1', 'Passw*'))
def test_avatars_hashtag_search(self): """Ensure user avatars appear when searching for posts with a hashtag """ user1 = create_account('user1', '*****@*****.**', 'Password') # Activate it activate(user1) # Signin self.client.post(url_for('auth.signin'), data={ 'username': '******', 'password': '******' }) # Ensure user avatar appear in the search when searching for hashtags image = io.BytesIO(open('tests/upload_test_files/otter.jpg').read()) self.client.post(url_for('users.settings_profile'), data={ 'upload': (image, 'otter.png') }, follow_redirects=True) # Get the user so we can see if the avatar is appearing user = get_user(user1) # Create a post to search for post1 = create_post(user1, 'user1', 'Hello #pjuuie\'s') resp = self.client.get(url_for('users.search', query='#pjuuie')) self.assertIn('<!-- list:post:%s -->' % post1, resp.data) self.assertIn(url_for('posts.get_upload', filename=user.get('avatar')), resp.data)
def test_followers_and_unfollowers_pagination_sizes(self): """Ensure that the followers and unfollowers feeds are correct if changing the feed size. """ users = [] # Creae 101 users (0 - 100) for i in xrange(101): users.append(create_account('user{}'.format(i), 'user{}@pjuu.com'.format(i), 'Password')) # Make user0 follow all users and visa versa for i in xrange(1, 101): follow_user(users[0], users[i]) follow_user(users[i], users[0]) FEED_ITEMS_PER_PAGE = app.config.get('FEED_ITEMS_PER_PAGE') # Check that the correct amount of users come back for follower and # following self.assertEqual(len(get_followers(users[0]).items), FEED_ITEMS_PER_PAGE) self.assertEqual(len(get_followers(users[0], per_page=25).items), 25) self.assertEqual(len(get_followers(users[0], per_page=50).items), 50) self.assertEqual(len(get_followers(users[0], per_page=100).items), 100) self.assertEqual(len(get_following(users[0]).items), FEED_ITEMS_PER_PAGE) self.assertEqual(len(get_following(users[0], per_page=25).items), 25) self.assertEqual(len(get_following(users[0], per_page=50).items), 50) self.assertEqual(len(get_following(users[0], per_page=100).items), 100)
def test_mention_real_user(self): """Find a user mentions (user does exist)""" user1 = create_account('user1', '*****@*****.**', 'Password1') mentions = parse_mentions('@user1 @user2') self.assertEqual(len(mentions), 1) self.assertEqual(mentions[0]['username'], 'user1') self.assertEqual(mentions[0]['user_id'], user1) self.assertEqual(mentions[0]['span'], (0, 6))
def test_surrounding_characters(self): """Can parse objects be in parenthesis""" user1 = create_account('user1', '*****@*****.**', 'Password1') activate(user1) links, mentions, hashtags = parse_post('(@user1), (pjuu.com), (#hash)') self.assertEqual(links[0]['link'], 'http://pjuu.com') self.assertEqual(mentions[0]['username'], 'user1') self.assertEqual(hashtags[0]['hashtag'], 'hash')
def test_unicode_character(self): """Do unicode characters break things.""" user1 = create_account('user1', '*****@*****.**', 'Password1') activate(user1) links, mentions, hashtags = parse_post('၍ @user1, ☂pjuu.com, 㒅 #hash') self.assertEqual(links[0]['link'], 'http://pjuu.com') self.assertEqual(mentions[0]['username'], 'user1') self.assertEqual(hashtags[0]['hashtag'], 'hash')
def test_alerts_pagination_sizes(self): """Check that the correct number of alerts are generated""" # Create 2 test users user1 = create_account('user1', '*****@*****.**', 'Password') user2 = create_account('user2', '*****@*****.**', 'Password') # Generate lots of following alerts for i in xrange(101): follow_user(user2, user1) unfollow_user(user2, user1) ALERT_ITEMS_PER_PAGE = app.config.get('ALERT_ITEMS_PER_PAGE') self.assertEqual(len(get_alerts(user1).items), ALERT_ITEMS_PER_PAGE) self.assertEqual(len(get_alerts(user1, per_page=25).items), 25) self.assertEqual(len(get_alerts(user1, per_page=50).items), 50) self.assertEqual(len(get_alerts(user1, per_page=100).items), 100)
def test_mention_real_user(self): """Find a user mentions (user does exist)""" user1 = create_account('user1', '*****@*****.**', 'Password1') activate(user1) mentions = parse_mentions('@user1 @user2') self.assertEqual(len(mentions), 1) self.assertEqual(mentions[0]['username'], 'user1') self.assertEqual(mentions[0]['user_id'], user1) self.assertEqual(mentions[0]['span'], (0, 6))
def test_userflags(self): """Ensure user flags are set as expected. """ user1 = create_account('user1', '*****@*****.**', 'Password') self.assertIsNotNone(user1) # Not active by default self.assertFalse(get_user(user1).get('active')) # TTL should be set self.assertIsNotNone(get_user(user1).get('ttl')) # Activate self.assertTrue(activate(user1)) self.assertTrue(get_user(user1).get('active')) self.assertIsNone(get_user(user1).get('ttl')) # Deactivate self.assertTrue(activate(user1, False)) self.assertFalse(get_user(user1).get('active')) # Invalid self.assertFalse(activate(None)) self.assertFalse(activate(K.NIL_VALUE)) # Banning, not by default self.assertFalse(get_user(user1).get('banned')) # Ban self.assertTrue(ban(user1)) self.assertTrue(get_user(user1).get('banned')) # Un-ban self.assertTrue(ban(user1, False)) self.assertFalse(get_user(user1).get('banned')) # Invalid self.assertFalse(ban(None)) self.assertFalse(ban(K.NIL_VALUE)) # OP (Over powered or Operator?) Account should not be op self.assertFalse(get_user(user1).get('op')) # Bite self.assertTrue(bite(user1)) self.assertTrue(get_user(user1).get('op')) # Un-bite self.assertTrue(bite(user1, False)) self.assertFalse(get_user(user1).get('op')) # Invalid self.assertFalse(bite(None)) self.assertFalse(bite(K.NIL_VALUE)) # Muted, can't post, not by default self.assertFalse(get_user(user1).get('muted')) # Mute self.assertTrue(mute(user1)) self.assertTrue(get_user(user1).get('muted')) # Un-mute self.assertTrue(mute(user1, False)) self.assertFalse(get_user(user1).get('muted')) # Invalid self.assertFalse(mute(None)) self.assertFalse(mute(K.NIL_VALUE))
def test_flag_control(self): """Ensure flagged posts appear in the dashboard""" user1 = create_account('user1', '*****@*****.**', 'Password') user2 = create_account('user2', '*****@*****.**', 'Password') # Make user1 OP bite(user1) activate(user1) post1 = create_post(user2, 'user2', 'post1') post2 = create_post(user2, 'user2', 'post2') comment1 = create_post(user2, 'user2', 'comment1', post1) comment2 = create_post(user2, 'user2', 'comment2', post1) # Flag all the posts flag_post(user1, post1) flag_post(user1, post2) flag_post(user1, comment1) flag_post(user1, comment2) self.client.post(url_for('auth.signin'), data={ 'username': '******', 'password': '******' }) resp = self.client.get(url_for('dashboard.dashboard')) s = '{0} - <a href="{1}">{2}</a>: <a href="{3}">{4}</a> ' + \ '[<a href="{5}">Unflag</a>]' self.assertIn( s.format( 1, url_for('users.profile', username='******'), 'user2', url_for('posts.view_post', username='******', post_id=post1), post1, url_for('posts.unflag_post', post_id=post1)), resp.data) self.assertIn( s.format( 1, url_for('users.profile', username='******'), 'user2', url_for('posts.view_post', username='******', post_id=post1), comment1, url_for('posts.unflag_post', post_id=comment1)) + ' (comment)', resp.data)
def test_delete_account(self): """ Test deleting an account from the frontend """ # Attempt to get to the delete_account view when not logged in resp = self.client.get(url_for('auth.delete_account'), follow_redirects=True) # We will just ensure we have been redirected to /signin self.assertEqual(resp.status_code, 200) # We should see a message saying we need to signin self.assertIn('You need to be logged in to view that', resp.data) # Let's create a user an login user1 = create_account('user1', '*****@*****.**', 'Password') # Activate the account self.assertTrue(activate(user1)) # Log the user in resp = self.client.post(url_for('auth.signin'), data={ 'username': '******', 'password': '******' }, follow_redirects=True) self.assertEqual(resp.status_code, 200) # Check that we can get to the delete_account page resp = self.client.get(url_for('auth.delete_account')) self.assertEqual(resp.status_code, 200) self.assertIn('This action is irreversible', resp.data) # Attempy to delete account. We are going to do this the other way # round. We will try and do it with an invalid password etc first. resp = self.client.post(url_for('auth.delete_account'), data={'password': '******'}, follow_redirects=True) self.assertEqual(resp.status_code, 200) self.assertIn('Oops! wrong password', resp.data) # That's all we can do to try and brake this. Let's delete our account resp = self.client.post(url_for('auth.delete_account'), data={'password': '******'}, follow_redirects=True) self.assertEqual(resp.status_code, 200) self.assertIn('Your account is being deleted', resp.data) # We are now back at signin. Let's check we can't login resp = self.client.post(url_for('auth.signin'), data={ 'username': '******', 'password': '******' }) self.assertEqual(resp.status_code, 200) self.assertIn('Invalid user name or password', resp.data)
def test_get_replies(self): """Test getting all replies for a post """ # Create two test users user1 = create_account('user1', '*****@*****.**', 'Password') user2 = create_account('user2', '*****@*****.**', 'Password') # Create a post for each user and a comment on each for both user post1 = create_post(user1, 'user1', 'Test post') post2 = create_post(user2, 'user2', 'Test post') # Ensure the comment lists are empty self.assertEqual(len(get_replies(post1).items), 0) self.assertEqual(len(get_replies(post2).items), 0) reply1 = create_post(user1, 'user1', 'Test comment', post1) reply2 = create_post(user1, 'user1', 'Test comment', post2) reply3 = create_post(user2, 'user2', 'Test comment', post1) reply4 = create_post(user2, 'user2', 'Test comment', post2) # Ensure each comment appears in each users list self.assertEqual(len(get_replies(post1).items), 2) self.assertEqual(len(get_replies(post2).items), 2) # Ensure the totals are correct self.assertEqual(get_replies(post1).total, 2) self.assertEqual(get_replies(post2).total, 2) # Ensure comments are in MongoDB comment_ids = \ [doc['_id'] for doc in m.db.posts.find({'reply_to': post1})] self.assertIn(reply1, comment_ids) self.assertIn(reply3, comment_ids) comment_ids = \ [doc['_id'] for doc in m.db.posts.find({'reply_to': post2})] self.assertIn(reply2, comment_ids) self.assertIn(reply4, comment_ids) # Delete 1 comment from post1 and ensure it does not exist delete_post(reply1) # Check that is has gone self.assertEqual(len(get_replies(post1).items), 1) self.assertEqual(get_replies(post1).total, 1)
def test_get_posts_pagination_sizes(self): """Ensure get_posts works with various pagination sizes""" user1 = create_account('user1', '*****@*****.**', 'Password') # Create loads of posts for i in xrange(100): create_post(user1, 'user1', 'Test post {}'.format(i)) FEED_ITEMS_PER_PAGE = app.config.get('FEED_ITEMS_PER_PAGE') self.assertEqual(len(get_posts(user1).items), FEED_ITEMS_PER_PAGE) self.assertEqual(len(get_posts(user1, per_page=25).items), 25) self.assertEqual(len(get_posts(user1, per_page=50).items), 50) self.assertEqual(len(get_posts(user1, per_page=100).items), 100)
def test_login_logout(self): """Can a user log in (sign in) and log out (sign out)? Involves a request context but IS a backend function. Sessions needed. """ user1 = create_account('user1', '*****@*****.**', 'Password') self.assertIsNotNone(user1) with app.test_request_context('/signin'): signin(user1) self.assertEqual(session.get('user_id', None), user1) signout() self.assertIsNone(session.get('user_id', None))
def test_dashboard_view(self): """Ensure basic stats show in dashboard""" user1 = create_account('user1', '*****@*****.**', 'Password') activate(user1) # Ensure we can't hit the endpoint not logged in # We WONT be redirected to login resp = self.client.get(url_for('dashboard.dashboard')) self.assertEqual(resp.status_code, 403) # Log in self.client.post(url_for('auth.signin'), data={ 'username': '******', 'password': '******' }) # Ensure we can't hit the endpoint if we are logged in but not op resp = self.client.get(url_for('dashboard.dashboard')) self.assertEqual(resp.status_code, 403) # Make the user OP bite(user1) # Check resp = self.client.get(url_for('dashboard.dashboard')) self.assertEqual(resp.status_code, 200) # Ensure there are some stats for the different libraries we expect # 'Server' is provided by the dashboard itself self.assertIn('Server', resp.data) # We can further check the 'Server' section as we need to anyway. self.assertIn('Hostname', resp.data) self.assertIn('Uname', resp.data) self.assertIn('Time UTC', resp.data) self.assertIn('Timestamp', resp.data) # Check the values we can self.assertIn(' '.join(os.uname()), resp.data) self.assertIn(socket.gethostname(), resp.data) # 'Auth' is provided by pjuu.auth self.assertIn('Auth', resp.data) # 'Posts' is provided by pjuu.posts self.assertIn('Posts', resp.data)
def test_create_post(self): """Tests creating and getting a post """ # Create a user to test creating post user1 = create_account('user1', '*****@*****.**', 'Password') # Create post post1 = create_post(user1, 'user1', 'Test post') # Check the post actually exists self.assertIsNotNone(post1) # Check that all the hash members are what we expect post = get_post(post1) self.assertIsNotNone(post) self.assertEqual(post.get('_id'), post1) self.assertEqual(post.get('user_id'), user1) self.assertEqual(post.get('body'), 'Test post') self.assertEqual(post.get('score'), 0) self.assertEqual(post.get('comment_count'), 0) # Check the memebers we don't know the answer to self.assertIsNotNone(post.get('created')) self.assertNotIn('upload', post) # Ensure this post is the users feed (populate_feed) self.assertIn(post1, r.zrange(K.USER_FEED.format(user1), 0, -1)) # Testing getting post with invalid arguments # Test getting a post that does not exist self.assertIsNone(get_post(K.NIL_VALUE)) # Create a post with an image image = io.BytesIO(open('tests/upload_test_files/otter.jpg').read()) post2 = create_post(user1, 'user1', 'Test post #2', upload=image) self.assertIsNotNone(post2) post = get_post(post2) self.assertIn('upload', post) self.assertIsNotNone(post.get('upload')) # Create a post with a broken image, ensure it's handled correctly image = io.BytesIO() post3 = create_post(user1, 'user1', 'Test post #3', upload=image) self.assertIsNone(post3) post3 = get_post(post3) self.assertIsNone(post3)
def test_dump_account(self): """ Simple check to make sure dump_account works in the views. Will simply check that a JSON response comes back. Don't worry this is pretty much a direct interface to the backend function of the same name. See BackendTestCase for more details. """ # Let's create a user an login user1 = create_account('user1', '*****@*****.**', 'Password') # Activate the account self.assertTrue(activate(user1)) # Attempt to acess the URL without being logged in resp = self.client.get(url_for('auth.dump_account')) self.assertEqual(resp.status_code, 302) # Log the user in resp = self.client.post(url_for('auth.signin'), data={ 'username': '******', 'password': '******' }, follow_redirects=True) self.assertEqual(resp.status_code, 200) # Check that a password confirmation is now required resp = self.client.get(url_for('auth.dump_account')) self.assertEqual(resp.status_code, 200) self.assertIn('This action will dump all of your data', resp.data) # Send password to the view resp = self.client.post(url_for('auth.dump_account'), data={'password': '******'}, follow_redirects=True) self.assertEqual(resp.status_code, 200) json_resp = json.loads(resp.data) self.assertEqual(json_resp['user']['username'], 'user1') # Test inputting the wrong password # Send password to the view resp = self.client.post(url_for('auth.dump_account'), data={'password': '******'}, follow_redirects=True) self.assertEqual(resp.status_code, 200) self.assertIn('Oops! wrong password', resp.data)
def test_permission_setting(self): """Test that a post can have correct permissions set""" user1 = create_account('user1', '*****@*****.**', 'Password') # Create post with each permission post1 = create_post(user1, 'user1', 'Test post', permission=0) post2 = create_post(user1, 'user1', 'Test post', permission=1) post3 = create_post(user1, 'user1', 'Test post', permission=2) post = get_post(post1) self.assertEqual(post.get('permission'), 0) post = get_post(post2) self.assertEqual(post.get('permission'), 1) post = get_post(post3) self.assertEqual(post.get('permission'), 2)