示例#1
0
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'
示例#2
0
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)
示例#4
0
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)
示例#5
0
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()
示例#9
0
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)
示例#10
0
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)