def test_view_post(self): """Verify post resources can be viewed""" self.simulate_post( PostCollectionResource.route, body=to_json(PostFormDtoSerializer, generate_post_form_dto()), headers=self.headers) post_collection_res = self.simulate_get(PostCollectionResource.route) created_post = post_collection_res.json.get('posts')[0] post_href = normalize_href(created_post.get('href')) self.assertEqual(created_post.get('views'), 0) post_view_href = normalize_href( next(ln.get('href') for ln in created_post.get('links') if ln.get('rel') == 'post-view')) self.simulate_put(post_view_href, headers=self.headers) post_res = self.simulate_get(post_href) self.assertEqual(post_res.json.get('views'), 1)
def test_user_avatar_disabled(self): """Ensure user avatar resources are not accessible when the feature is disabled.""" global settings settings.user.allow_avatar_capability = False save_settings(settings, False) user_res = self.simulate_get(UserResource.route, headers=self.headers) avatar_href = user_res.json.get('avatarHref') # verify avatar cannot be fetched self.assertEqual(avatar_href, '') user_links = user_res.json.get('links') # can currently double as both upload and delete, may be subject to change user_avatar_resource_href = normalize_href( find_link_href_json(user_links, BLOG_USER_RESOURCE_HREF_REL.USER_AVATAR_UPLOAD)) avatar_path = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'blog/static/default-avatar.png')) avatar_binary = open(avatar_path, 'rb').read() body, headers = create_multipart_form(avatar_binary, 'image', avatar_path, 'image/png') upload_headers = self.headers.copy() upload_headers.update(headers) # verify avatar cannot be uploaded avatar_res = self.simulate_post( user_avatar_resource_href, headers=upload_headers, body=body) self.assertEqual(avatar_res.status_code, 403) # verify avatar cannot be deleted avatar_res = self.simulate_delete(user_avatar_resource_href, headers=self.headers) self.assertEqual(avatar_res.status_code, 403)
def test_user_avatar_resource_s3(self): """Ensure a user can upload an avatar via s3 (this test was designed for fakes3)""" global settings settings.user.upload_avatar_s3 = True save_settings(settings, False) user_res = self.simulate_get(UserResource.route, headers=self.headers) user_links = user_res.json.get('links') # can currently double as both upload and delete, may be subject to change user_avatar_resource_href = normalize_href( find_link_href_json(user_links, BLOG_USER_RESOURCE_HREF_REL.USER_AVATAR_UPLOAD)) avatar_path = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'tests/resources/afro.jpg')) avatar_binary = open(avatar_path, 'rb').read() body, headers = create_multipart_form(avatar_binary, 'image', avatar_path, 'image/jpg') upload_headers = self.headers.copy() upload_headers.update(headers) # verify avatar can be uploaded avatar_res = self.simulate_post( user_avatar_resource_href, headers=upload_headers, body=body) self.assertEqual(avatar_res.status_code, 201) # verify avatar was stored in s3 user_res = self.simulate_get(UserResource.route, headers=self.headers) avatar_href = user_res.json.get('avatarHref') self.assertIn(f'http://{BLOG_FAKE_S3_HOST}/{BLOG_AWS_S3_BUCKET}/', avatar_href)
def test_core_post_resource(self): """Ensure a post resource can be created, fetched, updated, and deleted""" res = self.simulate_get(PostCollectionResource.route) self.assertEqual(res.status_code, 200) # verify no post resources returned in post collection self.assertEqual(len(res.json.get('posts')), 0) # verify posts are created as intended post_create_res = self.simulate_post( PostCollectionResource.route, body=to_json(PostFormDtoSerializer, generate_post_form_dto()), headers=self.headers) self.assertEqual(post_create_res.status_code, 201) elapsed_start = time.clock() * 1000 post_collection_res = self.simulate_get(PostCollectionResource.route) elapsed_delta = (time.clock() * 1000) - elapsed_start self.assertEqual(post_collection_res.status_code, 200) self.assertEqual(len(post_collection_res.json.get('posts')), 1) # verify caching works as intended elapsed_start = time.clock() * 1000 self.simulate_get(PostCollectionResource.route) cached_delta = (time.clock() * 1000) - elapsed_start self.assertGreater(elapsed_delta / 2, cached_delta) # measurement subject to change, cached response should take no longer than 3 ms self.assertLess(cached_delta, 3) # get resource href for created post created_post = post_collection_res.json.get('posts')[0] post_href = normalize_href(created_post.get('href')) # fetch post using extracted href post_res = self.simulate_get(post_href) self.assertEqual(created_post.get('title'), post_res.json.get('title')) self.assertEqual(created_post.get('description'), post_res.json.get('description')) self.assertEqual(created_post.get('content'), post_res.json.get('content')) self.assertEqual(created_post.get('author'), post_res.json.get('author')) # self.assertEqual(len(created_post.get('tags')), len(post_res.json.get('tags'))) # validate links for post in collection and payload from post resource expected_links = ('post-comment', 'post-like', 'post-view') for rel in expected_links: self.assertIsNotNone( next((ln for ln in created_post.get('links') if ln.get('rel') == rel), None)) self.assertIsNotNone( next((ln for ln in post_res.json.get('links') if ln.get('rel') == rel), None)) # update post resource and verify changes post_details = generate_post_form_dto() post_update_res = self.simulate_put( post_href, body=to_json(PostFormDtoSerializer, post_details), headers=self.headers) self.assertEqual(post_update_res.status_code, 204) updated_post_res = self.simulate_get(post_href) self.assertEqual(updated_post_res.json.get('title'), post_details.title) self.assertEqual(updated_post_res.json.get('description'), post_details.description) self.assertEqual(updated_post_res.json.get('content'), post_details.content) # delete post resource and validate expected behavior delete_post_res = self.simulate_delete(post_href, headers=self.headers) self.assertEqual(delete_post_res.status_code, 204) post_res = self.simulate_get(post_href) self.assertEqual(post_res.status_code, 404) post_collection_res = self.simulate_get(PostCollectionResource.route) self.assertEqual(len(post_collection_res.json.get('posts')), 0)
def test_comment_post(self): """Verify comment resources can be created, updated, and deleted""" self.simulate_post( PostCollectionResource.route, body=to_json(PostFormDtoSerializer, generate_post_form_dto()), headers=self.headers) post_collection_res = self.simulate_get(PostCollectionResource.route) created_post = post_collection_res.json.get('posts')[0] self.assertEqual(created_post.get('comments'), 0) post_href = normalize_href(created_post.get('href')) post_res = self.simulate_get(post_href) self.assertEqual(post_res.status_code, 200) self.assertEqual(len(post_res.json.get('comments')), 0) post_comment_href = normalize_href( next(ln.get('href') for ln in created_post.get('links') if ln.get('rel') == 'post-comment')) comment_form = generate_comment_form_dto() # verify comments are created as intended create_comment_res = self.simulate_post( post_comment_href, body=to_json(CommentFormDtoSerializer, comment_form), headers=self.headers) self.assertEqual(create_comment_res.status_code, 201) post_res = self.simulate_get(post_href) self.assertEqual(post_res.status_code, 200) self.assertEqual(len(post_res.json.get('comments')), 1) created_comment = post_res.json.get('comments')[0] self.assertEqual(created_comment.get('content'), comment_form.content) # verify coment content can be updated comment_href = normalize_href(created_comment.get('href')) new_comment_form = generate_comment_form_dto() update_comment_res = self.simulate_put( comment_href, body=to_json(CommentFormDtoSerializer, new_comment_form), headers=self.headers) self.assertEqual(update_comment_res.status_code, 204) comment_res = self.simulate_get(comment_href) self.assertEqual(comment_res.json.get('content'), new_comment_form.content) # verify comment resources can be deleted delete_comment_res = self.simulate_delete(comment_href, headers=self.headers) self.assertEqual(delete_comment_res.status_code, 204) comment_res = self.simulate_get(comment_href) self.assertEqual(comment_res.status_code, 404) post_res = self.simulate_get(post_href) self.assertEqual(len(post_res.json.get('comments')), 0)
def test_user_avatar_resource(self): """Ensure a user can upload and delete an avatar.""" user_res = self.simulate_get(UserResource.route, headers=self.headers) avatar_href = normalize_href(user_res.json.get('avatarHref')) avatar_res = self.simulate_get(avatar_href) # verify default avatar is served as expected self.assertEqual(avatar_res.status_code, 200) self.assertEqual(avatar_res.headers.get('content-type'), 'image/png') self.assertEqual(len(avatar_res.content), 6957) user_links = user_res.json.get('links') # can currently double as both upload and delete, may be subject to change user_avatar_resource_href = normalize_href( find_link_href_json(user_links, BLOG_USER_RESOURCE_HREF_REL.USER_AVATAR_UPLOAD)) avatar_path = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'tests/resources/afro.jpg')) avatar_binary = open(avatar_path, 'rb').read() body, headers = create_multipart_form(avatar_binary, 'image', avatar_path, 'image/jpeg') upload_headers = self.headers.copy() upload_headers.update(headers) # verify avatar can be uploaded avatar_res = self.simulate_post( user_avatar_resource_href, headers=upload_headers, body=body) self.assertEqual(avatar_res.status_code, 201) # verify uploaded avatar is served as expected avatar_res = self.simulate_get(avatar_href) self.assertEqual(avatar_res.status_code, 200) self.assertEqual(avatar_res.headers.get('content-type'), 'image/jpeg') self.assertEqual(len(avatar_res.content), len(avatar_binary) + 42) # verify avatar is deleted as expected avatar_res = self.simulate_delete(user_avatar_resource_href, headers=self.headers) self.assertEqual(avatar_res.status_code, 204) avatar_res = self.simulate_get(avatar_href) self.assertEqual(avatar_res.status_code, 200) self.assertEqual(avatar_res.headers.get('content-type'), 'image/png') self.assertEqual(len(avatar_res.content), 6957)