def test_publish_on_twitter_service(mock_get_twitter_api_object, mock_update_status, mock_update_with_media): mock_get_twitter_api_object.return_value = tweepy.api # Check post only with text post = f.create_post(image=None) services.publish_on_twitter(post.id) mock_get_twitter_api_object.assert_called_once_with(settings.TWITTER_OAUTH) mock_update_status.assert_called_once_with(status=post.text) # Check post with text and image post = f.create_post() post_instance = Post.objects.get(pk=post.id) image_file = post_instance.image.file.name mock_get_twitter_api_object.reset_mock() services.publish_on_twitter(post.id) mock_get_twitter_api_object.assert_called_once_with(settings.TWITTER_OAUTH) mock_update_with_media.assert_called_once_with( filename=image_file, status=post.text, file=post_instance.image ) # Raising a TweepError mock_update_with_media.side_effect = tweepy.error.TweepError('Error reason from twitter') with pytest.raises(exceptions.BadRequest) as exc: services.publish_on_twitter(post.id) assert exc.value.args[0] == 'Error reason from twitter'
def test_publish_on_facebook_service(mock_page_graph): post = f.create_post(image=None) publish_on_facebook(post.id) mock_page_graph.return_value.put_object.assert_called_with( parent_object=ANY, connection_name='feed', message=post.text) post = f.create_post(text=None) publish_on_facebook(post_id=post.id) mock_page_graph.return_value.put_photo.assert_called_with(image=ANY) post = f.create_post() publish_on_facebook(post_id=post.id) mock_page_graph.return_value.put_photo.assert_called_with( image=ANY, message=post.text)
def test_publish_on_linkedin_task( mock_publish_on_linkedin, mock_check_and_raise_error_from_linkedin_response): post = f.create_post() tasks.publish_on_linkedin_task(post.id) mock_publish_on_linkedin.assert_called_once_with(post.id) mock_check_and_raise_error_from_linkedin_response.assert_called_once_with( mock_publish_on_linkedin.return_value)
def test_publish_on_social_media_service(mock_publish_on_twitter_task): post = f.create_post(is_approved=True, posted_at='twitter', posted_time=None) assert post.is_posted is False services.publish_on_social_media() post.refresh_from_db() assert post.is_posted is True assert post.posted_time is not None mock_publish_on_twitter_task.assert_called_once_with(post.id)
def test_publishing_limited_posts(mock_publish_on_facebook_task, mock_settings): mock_settings.MAX_POSTS_AT_ONCE = 2 mock_settings.LIMIT_POSTS = False # Create an approved post with current time as scheduled time post = f.create_post(posted_at='fb', is_approved=True) publish_on_social_media_task() mock_publish_on_facebook_task.assert_called_once_with(post.id) post.refresh_from_db() assert post.is_posted is True assert post.posted_time is not None mock_settings.LIMIT_POSTS = True mock_publish_on_facebook_task.reset_mock() f.create_post(posted_at='fb', is_approved=True, n=3) publish_on_social_media_task() assert mock_publish_on_facebook_task.call_count == 2
def test_publish_on_linkedin_with_image(mock_upload_image_to_linkedin, mock_post, base_data): post, api_url_ugc, linkedin_auth, author, headers, post_data = base_data post = f.create_post() specific_content = post_data.get('specificContent') share_content = specific_content.get('com.linkedin.ugc.ShareContent') post_data_text = share_content.get('shareCommentary') post_data_text['text'] = post.text post_id = post.id post_instance = Post.objects.get(pk=post_id) mock_post.return_value = requests.Response() asset = mock.Mock() mock_upload_image_to_linkedin.return_value = asset specific_content = post_data.get('specificContent') share_content = specific_content.get('com.linkedin.ugc.ShareContent') image_media = [{ 'status': 'READY', 'description': { 'text': '' }, 'media': asset, 'title': { 'text': '' } }] share_content.update(shareMediaCategory='IMAGE', media=image_media) response_image = services.publish_on_linkedin(post_id) mock_upload_image_to_linkedin.assert_called_once_with( author, headers, post_instance, linkedin_auth, ) mock_post.assert_called_once_with(api_url_ugc, headers=headers, json=post_data) assert isinstance(response_image, requests.Response)
def base_data(client): post = f.create_post(image=None) # LinkedIn UGC(User Generated Content) API endpoint api_url_ugc = f'{settings.LINKEDIN_API_URL_BASE}ugcPosts' linkedin_auth = settings.LINKEDIN_AUTH author = f"urn:li:organization:{linkedin_auth['organization_id']}" headers = { 'X-Restli-Protocol-Version': '2.0.0', 'Content-Type': 'application/json', 'Authorization': f"Bearer {linkedin_auth['access_token']}" } post_data = { 'author': author, 'lifecycleState': 'PUBLISHED', 'specificContent': { 'com.linkedin.ugc.ShareContent': { 'shareCommentary': { 'text': post.text }, 'shareMediaCategory': 'NONE' }, }, 'visibility': { 'com.linkedin.ugc.MemberNetworkVisibility': 'PUBLIC' }, } return ( post, api_url_ugc, linkedin_auth, author, headers, post_data, )
def test_upload_image_to_linkedin( mock_json, mock_post, mock_check_and_raise_error_from_linkedin_response, base_data): post, api_url_ugc, linkedin_auth, author, headers, post_data = base_data post = f.create_post() post_id = post.id post_instance = Post.objects.get(pk=post_id) post_data_assets = { 'registerUploadRequest': { 'recipes': ['urn:li:digitalmediaRecipe:feedshare-image'], 'owner': author, 'serviceRelationships': [{ 'relationshipType': 'OWNER', 'identifier': 'urn:li:userGeneratedContent' }] } } api_url_assets = f'{settings.LINKEDIN_API_URL_BASE}assets?action=registerUpload' mock_post.return_value = requests.Response() # When response_asset status code is not 200 as no status code has been set services.upload_image_to_linkedin( author, headers, post_instance, linkedin_auth, ) mock_post.assert_called_once_with(api_url_assets, json=post_data_assets, headers=headers) mock_check_and_raise_error_from_linkedin_response.assert_called_once_with( mock_post.return_value) # When response_asset status code is 200 and response_upload_image status code is not 201 mock_post.return_value.status_code = status.HTTP_200_OK upload_url = mock.Mock() asset = mock.Mock() mock_json.return_value = { 'value': { 'uploadMechanism': { 'com.linkedin.digitalmedia.uploading.MediaUploadHttpRequest': { 'headers': {}, 'uploadUrl': upload_url, } }, 'mediaArtifact': mock.Mock(), 'asset': asset } } mock_post.reset_mock() mock_check_and_raise_error_from_linkedin_response.reset_mock() services.upload_image_to_linkedin( author, headers, post_instance, linkedin_auth, ) # bring back the file pointer to starting postion as it's already read once # when the above call is made. So that reading it again in assertion # doesn't fail. post_instance.image.file.seek(0) assert mock_post.call_count == 2 mock_post.assert_has_calls([ mock.call(api_url_assets, json=post_data_assets, headers=headers), mock.call(upload_url, data=post_instance.image.file.read(), headers={ 'Authorization': f"Bearer {linkedin_auth['access_token']}" }) ]) mock_check_and_raise_error_from_linkedin_response.assert_called_once_with( mock_post.return_value) # When response_asset status code is 200 and response_upload_image status code is 201 return_values = [requests.Response(), requests.Response()] return_values[0].status_code = status.HTTP_200_OK return_values[1].status_code = status.HTTP_201_CREATED mock_post.side_effect = return_values # Again bringing back the file pointer to starting postiion post_instance.image.file.seek(0) mock_post.reset_mock() mock_check_and_raise_error_from_linkedin_response.reset_mock() return_value = services.upload_image_to_linkedin( author, headers, post_instance, linkedin_auth, ) post_instance.image.file.seek(0) assert mock_post.call_count == 2 mock_post.assert_has_calls([ mock.call(api_url_assets, json=post_data_assets, headers=headers), mock.call(upload_url, data=post_instance.image.file.read(), headers={ 'Authorization': f"Bearer {linkedin_auth['access_token']}" }) ]) assert return_value == asset mock_check_and_raise_error_from_linkedin_response.assert_not_called()
def test_publish_on_twitter_task(mock_publish_on_twitter): post = f.create_post() tasks.publish_on_twitter_task(post.id) mock_publish_on_twitter.assert_called_once_with(post.id)
def test_publish_on_facebook_task(mock_publish_on_facebook): post = f.create_post() publish_on_facebook_task(post.id) mock_publish_on_facebook.assert_called_once_with(post.id)