def test_create_comment( user_client, reddit_factories, private_channel_and_contributor, mock_notify_subscribed_users, extra_params, extra_expected, score, ): # pylint: disable=too-many-arguments """Create a comment""" channel, user = private_channel_and_contributor post = reddit_factories.text_post("a post", user, channel=channel) url = reverse("comment-list", kwargs={"post_id": post.id}) resp = user_client.post(url, data={ "text": "reply_to_post 2", **extra_params }) assert resp.status_code == status.HTTP_201_CREATED assert resp.json() == { "author_id": user.username, "created": any_instance_of(str), "id": any_instance_of(str), "parent_id": None, "post_id": post.id, "score": 1, "text": "reply_to_post 2", "upvoted": True, "downvoted": False, "removed": False, "deleted": False, "subscribed": True, "profile_image": image_uri(user.profile), "author_name": user.profile.name, "author_headline": user.profile.headline, "edited": False, "comment_type": "comment", "num_reports": None, **extra_expected, } assert_properties_eq( Comment.objects.get(comment_id=resp.json()["id"]), { "author": user, "text": "reply_to_post 2", "score": score, "removed": False, "deleted": False, "edited": False, "created_on": any_instance_of(datetime), }, ) mock_notify_subscribed_users.assert_called_once_with( post.id, None, resp.json()["id"])
def test_create_article_post(user_client, private_channel_and_contributor): """ Create a new article post """ channel, user = private_channel_and_contributor url = reverse("post-list", kwargs={"channel_name": channel.name}) article_text = "some text" article_content = [{ "key": "value", "nested": { "number": 4 }, "text": article_text }] resp = user_client.post(url, { "title": "parameterized testing", "article_content": article_content }) assert resp.status_code == status.HTTP_201_CREATED assert resp.json() == { "title": "parameterized testing", "text": "", "article_content": article_content, "plain_text": article_text, "url": None, "url_domain": None, "cover_image": None, "thumbnail": None, "author_id": user.username, "created": any_instance_of(str), "upvoted": True, "removed": False, "deleted": False, "subscribed": True, "id": any_instance_of(str), "slug": "parameterized-testing", "num_comments": 0, "score": 1, "channel_name": channel.name, "channel_title": channel.title, "channel_type": "private", "profile_image": image_uri(user.profile), "author_name": user.profile.name, "author_headline": user.profile.headline, "edited": False, "stickied": False, "num_reports": None, "post_type": EXTENDED_POST_TYPE_ARTICLE, } article = Article.objects.filter(post__post_id=resp.json()["id"]) assert article.exists() assert article.first().content == article_content
def test_xpro_transform_courses(mock_xpro_courses_data): """Test that xpro courses data is correctly transformed into our normalized structure""" result = xpro.transform_courses(mock_xpro_courses_data) expected = [ { "course_id": course_data["readable_id"], "platform": PlatformType.xpro.value, "title": course_data["title"], "image_src": course_data["thumbnail_url"], "short_description": course_data["description"], "offered_by": xpro.OFFERED_BY, "published": any( map( lambda course_run: course_run.get("current_price", None), course_data["courseruns"], ) ), "topics": course_data.get("topics", []), "runs": [ { "run_id": course_run_data["courseware_id"], "platform": PlatformType.xpro.value, "start_date": any_instance_of(datetime, type(None)), "end_date": any_instance_of(datetime, type(None)), "enrollment_start": any_instance_of(datetime, type(None)), "enrollment_end": any_instance_of(datetime, type(None)), "best_start_date": _parse_datetime( course_run_data["enrollment_start"] or course_run_data["start_date"] ), "best_end_date": _parse_datetime( course_run_data["enrollment_end"] or course_run_data["end_date"] ), "offered_by": xpro.OFFERED_BY, "published": bool(course_run_data["current_price"]), "prices": [{"price": course_run_data["current_price"]}] if course_run_data["current_price"] else [], "instructors": [ {"full_name": instructor["name"]} for instructor in course_run_data["instructors"] ], } for course_run_data in course_data["courseruns"] ], } for course_data in mock_xpro_courses_data ] assert expected == result
def assert_api_call( client, url, payload, expected, expect_authenticated=False, expect_status=status.HTTP_200_OK, use_defaults=True, ): """Run the API call and perform basic assertions""" assert bool(get_user(client).is_authenticated) is False response = client.post(reverse(url), payload) actual = response.json() defaults = { "errors": [], "redirect_url": None, "extra_data": {}, "state": None, "provider": None, "flow": None, "partial_token": any_instance_of(str), } assert actual == ({**defaults, **expected} if use_defaults else expected) assert response.status_code == expect_status assert bool(get_user(client).is_authenticated) is expect_authenticated return actual
def test_send_notification( mocker, is_parent_comment, reddit_factories, private_channel_and_contributor ): """Tests send_notification""" channel, user = private_channel_and_contributor ns = NotificationSettingsFactory.create( user=user, comments_type=True, via_email=True, immediate=True ) notifier = comments.CommentNotifier(ns) send_messages_mock = mocker.patch("mail.api.send_messages") post = reddit_factories.text_post("just a post", user, channel=channel) comment = reddit_factories.comment("just a comment", user, post_id=post.id) if is_parent_comment: subscription = Subscription.objects.create( user=user, comment_id=comment.id, post_id=post.id ) comment = reddit_factories.comment("reply comment", user, comment_id=comment.id) else: subscription = Subscription.objects.create(user=user, post_id=post.id) event = notifier.create_comment_event(subscription, comment.id) note = event.email_notification note.state = EmailNotification.STATE_SENDING note.save() notifier.send_notification(note) send_messages_mock.assert_called_once_with([any_instance_of(EmailMessage)])
def test_send_notification(mocker, user): """Tests send_notification""" ns = NotificationSettingsFactory.create(via_email=True, weekly=True) notifier = frontpage.FrontpageDigestNotifier(ns) post = PostFactory.create() send_messages_mock = mocker.patch("mail.api.send_messages") serializer_mock = mocker.patch("channels.serializers.posts.PostSerializer") serializer_mock.return_value.data = { "id": post.post_id, "title": "post's title", "slug": "a_slug", "channel_name": "micromasters", "channel_title": "MicroMasters", "created": now_in_utc().isoformat(), "author_id": user.username, } submission = mocker.Mock(id=post.post_id, created=int(now_in_utc().timestamp()), stickied=False) api_mock = mocker.patch("channels.api.Api") api_mock.return_value.front_page.return_value = [submission] note = EmailNotificationFactory.create( user=ns.user, notification_type=ns.notification_type, sending=True) notifier.send_notification(note) serializer_mock.assert_called_once_with( PostProxy(submission, post), context={"current_user": note.user}) send_messages_mock.assert_called_once_with([any_instance_of(EmailMessage)])
def test_create_url_post_existing_meta(user_client, private_channel_and_contributor, mocker, settings): """ Create a new url post """ settings.EMBEDLY_KEY = "FAKE" channel, user = private_channel_and_contributor link_url = "http://micromasters.mit.edu/🐨" thumbnail = "http://fake/thumb.jpg" embedly_stub = mocker.patch("channels.utils.get_embedly_summary") LinkMetaFactory.create(url=link_url, thumbnail=thumbnail) url = reverse("post-list", kwargs={"channel_name": channel.name}) resp = user_client.post(url, {"title": "url title 🐨", "url": link_url}) embedly_stub.assert_not_called() assert resp.status_code == status.HTTP_201_CREATED assert resp.json() == { "title": "url title 🐨", "post_type": LINK_TYPE_LINK, "url": link_url, "url_domain": "micromasters.mit.edu", "cover_image": None, "thumbnail": thumbnail, "text": None, "article_content": None, "plain_text": None, "author_id": user.username, "created": any_instance_of(str), "upvoted": True, "id": any_instance_of(str), "slug": "url-title", "num_comments": 0, "removed": False, "deleted": False, "subscribed": True, "score": 1, "channel_name": channel.name, "channel_title": channel.title, "channel_type": channel.channel_type, "profile_image": image_uri(user.profile), "author_name": user.profile.name, "author_headline": user.profile.headline, "edited": False, "stickied": False, "num_reports": None, }
def test_any_instance_of(): """Tests any_instance_of()""" any_number = any_instance_of(int, float) assert any_number == 0.405 assert any_number == 8_675_309 assert any_number != "not a number" assert any_number != {} assert any_number != []
def test_create_text_post(user_client, private_channel_and_contributor): """ Create a new text post """ channel, user = private_channel_and_contributor url = reverse("post-list", kwargs={"channel_name": channel.name}) resp = user_client.post(url, { "title": "parameterized testing", "text": "tests are great" }) assert resp.status_code == status.HTTP_201_CREATED assert resp.json() == { "title": "parameterized testing", "text": "tests are great", "article_content": None, "plain_text": "tests are great", "url": None, "url_domain": None, "cover_image": None, "thumbnail": None, "author_id": user.username, "created": any_instance_of(str), "upvoted": True, "removed": False, "deleted": False, "subscribed": True, "id": any_instance_of(str), "slug": "parameterized-testing", "num_comments": 0, "score": 1, "channel_name": channel.name, "channel_title": channel.title, "channel_type": channel.channel_type, "profile_image": image_uri(user.profile), "author_name": user.profile.name, "author_headline": user.profile.headline, "edited": False, "stickied": False, "num_reports": None, "post_type": LINK_TYPE_SELF, }
def test_send_notification(notifier, mocker): """Tests send_notification""" send_messages_mock = mocker.patch("mail.api.send_messages") note = EmailNotificationFactory.create( user=notifier.user, notification_type=notifier.notification_settings.notification_type, sending=True, ) notifier.send_notification(note) send_messages_mock.assert_called_once_with([any_instance_of(EmailMessage)])
def test_create_comment_reply_to_comment( user_client, reddit_factories, private_channel_and_contributor, mock_notify_subscribed_users, ): """Create a comment that's a reply to another comment""" channel, user = private_channel_and_contributor post = reddit_factories.text_post("a post", user, channel=channel) comment = reddit_factories.comment("comment", user, post_id=post.id) url = reverse("comment-list", kwargs={"post_id": post.id}) resp = user_client.post(url, data={ "text": "reply_to_comment 3", "comment_id": comment.id }) assert resp.status_code == status.HTTP_201_CREATED assert resp.json() == { "author_id": user.username, "created": any_instance_of(str), "id": any_instance_of(str), "parent_id": comment.id, "post_id": post.id, "score": 1, "text": "reply_to_comment 3", "upvoted": True, "downvoted": False, "removed": False, "deleted": False, "subscribed": True, "profile_image": image_uri(user.profile), "author_name": user.profile.name, "author_headline": user.profile.headline, "edited": False, "comment_type": "comment", "num_reports": None, } mock_notify_subscribed_users.assert_called_once_with( post.id, comment.id, resp.json()["id"])
def test_context_for_user(settings, test_user, extra_context): """Tests that context_for_user returns the expected values""" user_ctx = ({ "user": test_user, "anon_token": any_instance_of(str) } if test_user else {}) assert context_for_user(user=test_user, extra_context=extra_context) == { "base_url": settings.SITE_BASE_URL, "site_name": get_default_site().title, **(extra_context or {}), **user_ctx, }
def test_create_or_update_micromasters_social_auth(user): """Test that we create a MM social auth""" username = "******" email = "test@localhost" email2 = "test2@localhost" assert UserSocialAuth.objects.count() == 0 assert (api.create_or_update_micromasters_social_auth( user, username, {"email": email}) is not None) assert UserSocialAuth.objects.count() == 1 social = UserSocialAuth.objects.first() assert social.user == user assert social.uid == username assert social.provider == "micromasters" assert social.extra_data == { "email": email, "username": username, "auth_time": any_instance_of(int), } # should be the same one as before, except email has updated assert (api.create_or_update_micromasters_social_auth( user, username, {"email": email2}) == social) social.refresh_from_db() assert social.user == user assert social.uid == username assert social.extra_data == { "email": email2, "username": username, "auth_time": any_instance_of(int), } assert UserSocialAuth.objects.count() == 1
def test_send_verification_email(mocker, rf): """Test that send_verification_email sends an email with the link in it""" send_messages_mock = mocker.patch("mail.api.send_messages") email = "test@localhost" request = rf.post(reverse("social:complete", args=("email", )), {"email": email}) # social_django depends on request.sesssion, so use the middleware to set that SessionMiddleware().process_request(request) strategy = load_strategy(request) backend = load_backend(strategy, EmailAuth.name, None) code = mocker.Mock(code="abc") verification_api.send_verification_email(strategy, backend, code, "def") send_messages_mock.assert_called_once_with([any_instance_of(EmailMessage)]) email_body = send_messages_mock.call_args[0][0][0].body assert "/signup/confirm/?verification_code=abc&partial_token=def" in email_body
def test_transform_course( openedx_config, openedx_extract_transform, mitx_course_data, has_runs, is_course_deleted, is_course_run_deleted, ): # pylint: disable=too-many-arguments """Test that the transform function normalizes and filters out data""" extracted = mitx_course_data["results"] expected = extracted if not is_course_deleted and has_runs else [] for course in extracted: if not has_runs: course["course_runs"] = [] if is_course_deleted: course["title"] = f"[delete] {course['title']}" if is_course_run_deleted: for run in course["course_runs"]: run["title"] = f"[delete] {run['title']}" assert openedx_extract_transform.transform(extracted) == [ { "title": "The Analytics Edge", "course_id": "MITx+15.071x", "short_description": "short_description", "full_description": "full description", "platform": openedx_config.platform, "offered_by": [{"name": openedx_config.offered_by}], "image_src": "https://prod-discovery.edx-cdn.org/media/course/image/ff1df27b-3c97-42ee-a9b3-e031ffd41a4f-747c9c2f216e.small.jpg", "image_description": "Image description", "last_modified": any_instance_of(datetime), "topics": [{"name": "Data Analysis & Statistics"}], "url": f"{openedx_config.alt_url}MITx+15.071x/course/", "runs": [] if is_course_run_deleted else [ { "availability": "Starting Soon", "best_end_date": "2019-05-22T23:30:00Z", "best_start_date": "2019-02-20T15:00:00Z", "run_id": "course-v1:MITx+15.071x+1T2019", "end_date": "2019-05-22T23:30:00Z", "platform": openedx_config.platform, "enrollment_end": None, "enrollment_start": None, "full_description": "<p>Full Description</p>", "image_description": None, "image_src": "https://prod-discovery.edx-cdn.org/media/course/image/ff1df27b-3c97-42ee-a9b3-e031ffd41a4f-747c9c2f216e.small.jpg", "instructors": [ {"first_name": "Dimitris", "last_name": "Bertsimas"}, {"first_name": "Allison", "last_name": "O'Hair"}, ], "language": "en-us", "last_modified": any_instance_of(datetime), "level": "Intermediate", "offered_by": [{"name": openedx_config.offered_by}], "prices": [ { "mode": "verified", "price": "150.00", "upgrade_deadline": "2019-03-20T15:00:00Z", }, {"mode": "audit", "price": "0.00", "upgrade_deadline": None}, ], "semester": "spring", "short_description": "short_description", "start_date": "2019-02-20T15:00:00Z", "title": "The Analytics Edge", "url": f"{openedx_config.alt_url}course-v1:MITx+15.071x+1T2019/course/", "year": 2019, } ], "raw_json": course, } for course in expected ]