def test_get_membership_ids_needing_sync(patched_users_api): """ Tests that get_membership_ids_needing_sync only returns ids for the correct records """ user1 = UserFactory.create() user2 = UserFactory.create() user3 = UserFactory.create() with mute_signals(post_save): user3.profile.delete() member_channels = [ChannelFactory.create() for _ in range(4)] nonmember_channels = [ChannelFactory.create() for _ in range(3)] # these should show up in results memberships_to_add = [ PercolateQueryMembership.objects.create(user=user1, query=channel.query, needs_update=True, is_member=True) for channel in member_channels ] memberships_to_remove = [ PercolateQueryMembership.objects.create(user=user1, query=channel.query, needs_update=True, is_member=False) for channel in nonmember_channels ] # these shouldn't show up in results memberships_add_no_update = [ PercolateQueryMembership.objects.create(user=user2, query=channel.query, needs_update=False, is_member=True) for channel in member_channels ] memberships_remove_no_update = [ PercolateQueryMembership.objects.create(user=user2, query=channel.query, needs_update=False, is_member=False) for channel in nonmember_channels ] memberships_add_no_profile = [ PercolateQueryMembership.objects.create(user=user3, query=channel.query, needs_update=True, is_member=True) for channel in member_channels ] memberships_remove_no_profile = [ PercolateQueryMembership.objects.create(user=user3, query=channel.query, needs_update=True, is_member=False) for channel in nonmember_channels ] results = api.get_membership_ids_needing_sync() for membership in memberships_to_add + memberships_to_remove: assert membership.id in results for membership in ( memberships_add_no_update + memberships_remove_no_update + memberships_add_no_profile + memberships_remove_no_profile ): assert membership.id not in results
def setUp(self): super().setUp() self.request_data = self.request_data.copy() self.request_data['send_automatic_emails'] = True for email in self.email_results: UserFactory.create(email=email) self.automatic_email = AutomaticEmailFactory.create() self.search_obj = create_search_obj( user=self.staff, search_param_dict=self.request_data['search_request'], filter_on_email_optin=True, )
def setUpTestData(cls): super(APITests, cls).setUpTestData() # create an user cls.user = UserFactory.create() # create the programs cls.program1 = ProgramFactory.create(live=True) cls.program2 = ProgramFactory.create(live=True)
def test_list_view(self): self.account = AccountFactory() self.user = UserFactory(accounts=[self.account]) self.login_member() resp = self.client.get(reverse('accounts:boards')) self.assertEqual(resp.status_code, 200) self.assertContains(resp, 'data-account', 1)
def setUpTestData(cls): """Create a program and user to test with""" super().setUpTestData() cls.program = ProgramFactory.create() cls.user = UserFactory.create() cls.context = {"request": Mock(user=cls.user)}
def test_ordering_get_membership_ids_needing_sync(patched_users_api): """Test that get_membership_ids_needing_sync returns ordered list based on is_member (True before False) and updated_on (most recent first).""" users = [UserFactory.create() for _ in range(4)] channel = ChannelFactory.create() memberships_is_member_true = [ PercolateQueryMembership.objects.create(user=user, query=channel.query, needs_update=True, is_member=True) for user in users[:2] ] memberships_is_member_false = [ PercolateQueryMembership.objects.create(user=user, query=channel.query, needs_update=True, is_member=False) for user in users[2:] ] memberships_is_member_true.reverse() memberships_is_member_false.reverse() expected_order = [] for membership in memberships_is_member_true + memberships_is_member_false: expected_order.append(membership.id) results = api.get_membership_ids_needing_sync() assert expected_order == list(results)
def test_student_id_should_be_blank_if_not_yet_saved(self): """test student id when model instance not yet saved""" with mute_signals(post_save): user = UserFactory() profile = Profile(user=user) assert profile.student_id is None assert profile.pretty_printed_student_id is ''
def test_add_channel_channel_already_exists(mock_staff_client, patched_users_api): """Channel already exists with that channel name""" response_409 = Response() response_409.status_code = statuses.HTTP_409_CONFLICT mock_staff_client.channels.create.return_value = response_409 title = "title" name = "name" description = "public description" channel_type = "private" input_search = Search.from_dict({"unmodified": "search"}) role = RoleFactory.create() mod = UserFactory.create() with pytest.raises(ChannelAlreadyExistsException): api.add_channel( original_search=input_search, title=title, name=name, description=description, channel_type=channel_type, program_id=role.program.id, creator_id=mod.id, ) mock_staff_client.channels.create.assert_called_once_with( title=title, name=name, description=description, channel_type=channel_type, )
def test_creates_order(self): """ An order is created using create_unfulfilled_order and a payload is generated using generate_cybersource_sa_payload """ course_key = 'course_key' user = UserFactory.create() self.client.force_login(user) order = MagicMock() payload = {'a': 'payload'} with patch( 'ecommerce.views.create_unfulfilled_order', autospec=True, return_value=order, ) as create_mock, patch( 'ecommerce.views.generate_cybersource_sa_payload', autospec=True, return_value=payload, ) as generate_mock: resp = self.client.post(reverse('checkout'), {'course_id': course_key}, format='json') assert resp.status_code == status.HTTP_200_OK assert resp.json() == { 'payload': payload, 'url': CYBERSOURCE_SECURE_ACCEPTANCE_URL, } assert create_mock.call_count == 1 assert create_mock.call_args[0] == (course_key, user) assert generate_mock.call_count == 1 assert generate_mock.call_args[0] == (order, )
def create_purchasable_course_run(): """ Creates a purchasable course run and an associated user """ course_run = CourseRunFactory.create(course__program__live=True) CoursePriceFactory.create(course_run=course_run, is_valid=True) user = UserFactory.create() return course_run, user
def setUpTestData(cls): """ Create a user """ with mute_signals(post_save): cls.user1 = UserFactory.create() username = "******".format(cls.user1.username) cls.user1.social_auth.create(provider=EdxOrgOAuth2.name, uid=username) cls.url1 = reverse('profile-detail', kwargs={'user': username}) with mute_signals(post_save): cls.user2 = UserFactory.create() username = "******".format(cls.user2.username) cls.user2.social_auth.create(provider=EdxOrgOAuth2.name, uid=username) cls.url2 = reverse('profile-detail', kwargs={'user': username})
def test_normal_users_cant_get(self): """ normal users shouldnt be able to get any data """ normal_user = UserFactory.create() self.client.force_login(normal_user) response = self.client.get(self.url) assert response.status_code == status.HTTP_403_FORBIDDEN
def setUp(self): super(CanSeeIfNotPrivateTests, self).setUp() with mute_signals(post_save): self.other_user = other_user = UserFactory.create() username = "******".format(other_user.username) social_auth = other_user.social_auth.create( provider=EdxOrgOAuth2.name, uid=username) self.other_user_id = social_auth.uid ProfileFactory.create(user=other_user, verified_micromaster_user=False) with mute_signals(post_save): self.profile_user = profile_user = UserFactory.create() username = "******".format(profile_user.username) social_auth = profile_user.social_auth.create( provider=EdxOrgOAuth2.name, uid=username) self.profile_user_id = social_auth.uid
def setUpTestData(cls): super(RefreshTest, cls).setUpTestData() # create an user cls.user = UserFactory.create() # create a social auth for the user cls.user.social_auth.create(provider=EdxOrgOAuth2.name, uid="{}_edx".format(cls.user.username), extra_data=social_extra_data)
def setUpTestData(cls): cls.staff_user = UserFactory.create() cls.program = ProgramFactory.create() Role.objects.create( user=cls.staff_user, program=cls.program, role=Staff.ROLE_ID, ) cls.url = reverse('automatic_email_api-list')
def test_valid_course_id(self): """ If course_id is not present in payload a ValidationError is raised """ user = UserFactory.create() self.client.force_login(user) resp = self.client.post(reverse('checkout'), {}, format='json') assert resp.status_code == status.HTTP_400_BAD_REQUEST assert resp.json() == ['Missing course_id']
def test_session_set(self): self.account = AccountFactory() self.user = UserFactory(accounts=[self.account]) self.client.login(username=self.user.email, password='******') url = reverse('accounts:boards') data = {'account_id': self.account.id} resp = self.ajax(url, data) self.assertEqual(resp.status_code, 200) self.assertEqual(get_current_account(self.client), self.account)
def setUpTestData(cls): """Create a program and user to test with""" super().setUpTestData() cls.program = ProgramFactory.create() cls.user = UserFactory.create() cls.context = { "request": Mock(user=cls.user) }
def test_saves_linkedin_response(self): """Happy path""" backend = mock.Mock() backend.name = 'linkedin-oauth2' user = UserFactory.create() response = {'test': 'works'} update_from_linkedin(backend, user, response) profile = Profile.objects.get(user=user) assert profile.linkedin == {'test': 'works'}
def test_normal_users_cant_patch(self): """ A non-staff user shouldn't be able to issue a PATCH request """ normal_user = UserFactory.create() self.client.force_login(normal_user) automatic = AutomaticEmailFactory.create(staff_user=self.staff_user) url = reverse('automatic_email_api-detail', kwargs={'email_id': automatic.id}) response = self.client.patch(url, {}, format='json') assert response.status_code == status.HTTP_403_FORBIDDEN
def test_login_redirect_dashboard(self): """ A student should be directed to /dashboard """ student = UserFactory.create() mock_strategy = mock.Mock() mock_strategy.session.load.return_value = {} mock_strategy.session.get.return_value = {} backend = edxorg.EdxOrgOAuth2(strategy=mock_strategy) pipeline_api.update_profile_from_edx(backend, student, {}, False, **{'edx_profile': self.mocked_edx_profile}) mock_strategy.session_set.assert_called_with('next', '/dashboard')
def setUpTestData(cls): super(RefreshTest, cls).setUpTestData() # create an user cls.user = UserFactory.create() # create a social auth for the user cls.user.social_auth.create( provider=EdxOrgOAuth2.name, uid="{}_edx".format(cls.user.username), extra_data= '{"access_token": "fooooootoken", "refresh_token": "baaaarrefresh"}' )
def create(cls, **kwargs): """ Overrides default ProgramEnrollment object creation for the factory. """ user = kwargs.get('user', UserFactory.create()) program = kwargs.get('program', ProgramFactory.create()) course = CourseFactory.create(program=program) course_run = CourseRunFactory.create(course=course) CachedEnrollmentFactory.create(user=user, course_run=course_run) CachedCertificateFactory.create(user=user, course_run=course_run) program_enrollment = ProgramEnrollment.objects.create(user=user, program=program) return program_enrollment
def test_sync_discussion_users_sync_with_email_optin_enabled( settings, mocker, patched_users_api): """ Test that sync_discussion_users call the api if enabled and for only users with a profile and not already synchronized """ users = [UserFactory.create() for _ in range(5)] for user in users[1:]: # Delete DiscussionUser so it will get backfilled user.discussion_user.delete() user_no_profile = UserFactory.create() user_no_profile.profile.delete() mock_api = mocker.patch('discussions.api.create_or_update_discussion_user', autospec=True) tasks.force_sync_discussion_users() assert mock_api.call_count == len(users) for user in users: mock_api.assert_any_call(user.id, allow_email_optin=True) with pytest.raises(AssertionError): mock_api.assert_any_call(user_no_profile.id, allow_email_optin=True)
def test_download_link_forbidden(self): account = AccountFactory() member = UserFactory(accounts=[account]) self.client.login(username=member.email, password='******') session = self.client.session session['current_account_id'] = account.id session.save() document = DocumentFactory(user=self.admin, folder=Folder.objects.get_account_root(self.account)) url = reverse('documents:download', kwargs={'document_id': document.pk}) response = self.client.get(url, follow=True) self.assertEqual(response.status_code, 404)
def test_login_redirect_next(self): """ A student should be directed to what's in the next query parameter """ student = UserFactory.create() next_url = "/x/y?a=bc" mock_strategy = mock.Mock() mock_strategy.session.load.return_value = {"next": next_url} mock_strategy.session.get.return_value = {} backend = edxorg.EdxOrgOAuth2(strategy=mock_strategy) pipeline_api.update_profile_from_edx(backend, student, {}, False, **{'edx_profile': self.mocked_edx_profile}) mock_strategy.session_set.assert_called_with('next', next_url)
def test_login_redirect_next_for_user_already_logged_in(self): """ A student should be directed to what's in the next query parameter if user is already logged in to MM. """ student = UserFactory.create() next_url = "/discussion" mock_strategy = mock.Mock() mock_strategy.session.load.return_value = {} mock_strategy.session.get.return_value = next_url backend = edxorg.EdxOrgOAuth2(strategy=mock_strategy) pipeline_api.update_profile_from_edx(backend, student, {}, False, **{'edx_profile': self.mocked_edx_profile}) mock_strategy.session_set.assert_called_with('next', next_url)
def create_init_data(self): from committees.models import Committee from profiles.models import User, Membership from accounts.factories import AccountFactory from profiles.factories import AdminFactory, UserFactory from meetings.factories import MeetingFactory from committees.factories import CommitteeFactory from django.contrib.contenttypes.models import ContentType from dashboard.models import RecentActivity from meetings.models import Meeting self.create_manual_migrations_if_needed() self.account = AccountFactory() self.admin = AdminFactory(accounts=[self.account]) UserFactory.create_batch(5, accounts=[self.account]) CommitteeFactory.create_batch(5) for membership in Membership.objects.filter(user__in=User.objects.select_related().exclude(is_superuser=True)): membership.committees.add(*random.sample(set(Committee.objects.filter(account_id=membership.account_id)), 2)) # Set last membership as comittee chairman (comittee_set) membership.committee_set.add(*random.sample(set(Committee.objects.filter(account_id=membership.account_id)), 1)) self.meetings = MeetingFactory.create_batch(2) # Document creation is broken and needs fixing # for meeting in self.meetings: # DocumentFactory.create_batch(2, meeting=meeting) self.membership = Membership.objects.filter(is_admin=False, account=self.account).order_by('pk')[0] self.membership_admin = Membership.objects.filter(is_admin=True, account=self.account)[0] self.user = self.membership.user for meeting in self.meetings: RecentActivity.objects.create(init_user=self.user, account=self.account, content_type=ContentType.objects.get_for_model(Meeting), object_id=meeting.id, action_flag=RecentActivity.ADDITION)
def test_dashboard_recent_save_committee_change(self): self.login_admin() url = reverse('committees:update', kwargs={ 'pk': self.committee.pk, 'url': self.account.url }) data = { 'name': self.committee.name, 'chairman': list(self.committee.chairman.all().values_list('id', flat=True)), 'members': list(self.committee.memberships.all().values_list('id', flat=True)), 'summary': self.committee.summary, 'description': self.committee.description, 'account': self.account } user2 = UserFactory(accounts=[self.account]) data['members'].append(user2.get_membership(account=self.account).id) mail.outbox = [] response = self.client.post(url, data, follow=True) updated_committee_members = list( Committee.objects.get( id=self.committee.id).memberships.all().values_list('id', flat=True)) self.assertItemsEqual(updated_committee_members, data['members']) self.assertEqual(response.status_code, 200) self.assertContains(response, 'Committee was changed successfully.') self.assertTrue(len(RecentActivity.objects.all()) > 0) for item in RecentActivity.objects.all(): self.assertEqual(item.content_object.name, data['name']) self.assertEqual(item.content_object.account, data['account']) self.assertEqual(item.init_user, self.admin) self.assertEqual(item.action_flag, RecentActivity.CHANGE) self.assertEqual(len(mail.outbox), 0)
def setUp(self): """ Set up class """ super(EdxPipelineApiTest, self).setUp() self.user = UserFactory() self.user.social_auth.create( provider='not_edx', ) self.user.social_auth.create( provider=edxorg.EdxOrgOAuth2.name, uid="{}_edx".format(self.user.username), ) self.user_profile = Profile.objects.get(user=self.user) self.mocked_edx_profile = { 'account_privacy': 'all_users', 'bio': 'this is my personal profile text', 'country': 'IT', 'date_joined': '2016-03-17T20:37:51Z', 'email': '*****@*****.**', 'gender': 'f', 'goals': None, 'is_active': True, 'language_proficiencies': [{'code': 'it'}], 'level_of_education': 'p', 'mailing_address': None, 'name': 'dummy user', 'profile_image': { 'has_image': True, 'image_url_full': 'https://edx.org/full.jpg', 'image_url_large': 'https://edx.org/large.jpg', 'image_url_medium': 'https://edx.org/medium.jpg', 'image_url_small': 'https://edx.org/small.jpg' }, 'requires_parental_consent': False, 'username': get_social_username(self.user), 'year_of_birth': 1986, "work_history": [ { "id": 1, "city": "NY", "state_or_territory": "NY", "country": "USA", "company_name": "XYZ-ABC", "position": "SSE", "industry": "IT", "end_date": "2016-05-17T17:14:00Z", "start_date": "2016-05-28T17:14:06Z" } ] }
def test_save_and_log_model(self): """ Tests that the save_model() function on OrderAdmin creates an OrderAudit entry """ assert OrderAudit.objects.count() == 0 order = OrderFactory.create() admin = OrderAdmin(model=order, admin_site=Mock()) mock_request = Mock(user=UserFactory.create()) admin.save_model(request=mock_request, obj=admin.model, form=Mock(), change=Mock()) assert OrderAudit.objects.count() == 1
def test_cant_edit_if_not_owner(self): """ Users are not allowed to edit if it's not their profile. """ perm = CanEditIfOwner() other_user = UserFactory.create() for method in ('POST', 'PATCH', 'PUT'): with mute_signals(post_save): profile = ProfileFactory.create( account_privacy=Profile.PUBLIC_TO_MM) request = Mock(method=method, user=other_user) assert not perm.has_object_permission(request, None, profile)
def test_login_redirect_learners(self): """ Staff or instructors should be directed to /learners """ for role in [Staff.ROLE_ID, Instructor.ROLE_ID]: user = UserFactory.create() Role.objects.create(user=user, role=role, program=ProgramFactory.create()) mock_strategy = mock.Mock() mock_strategy.session.load.return_value = {} mock_strategy.session.get.return_value = {} backend = edxorg.EdxOrgOAuth2(strategy=mock_strategy) pipeline_api.update_profile_from_edx(backend, user, {}, False, **{'edx_profile': self.mocked_edx_profile}) mock_strategy.session_set.assert_called_with('next', '/learners')
def test_login_redirect_dashboard(self): """ A student should be directed to /dashboard """ student = UserFactory.create() mock_strategy = mock.Mock() mock_strategy.session.load.return_value = {} mock_strategy.session.get.return_value = {} backend = edxorg.EdxOrgOAuth2(strategy=mock_strategy) pipeline_api.update_profile_from_edx( backend, student, {}, False, **{'edx_profile': self.mocked_edx_profile}) mock_strategy.session_set.assert_called_with('next', '/dashboard')
def test_login_redirect_next_for_user_already_logged_in(self): """ A student should be directed to what's in the next query parameter if user is already logged in to MM. """ student = UserFactory.create() next_url = "/discussion" mock_strategy = mock.Mock() mock_strategy.session.load.return_value = {} mock_strategy.session.get.return_value = next_url backend = edxorg.EdxOrgOAuth2(strategy=mock_strategy) pipeline_api.update_profile_from_edx( backend, student, {}, False, **{'edx_profile': self.mocked_edx_profile}) mock_strategy.session_set.assert_called_with('next', next_url)
def test_login_redirect_next(self): """ A student should be directed to what's in the next query parameter """ student = UserFactory.create() next_url = "/x/y?a=bc" mock_strategy = mock.Mock() mock_strategy.session.load.return_value = {"next": next_url} mock_strategy.session.get.return_value = {} backend = edxorg.EdxOrgOAuth2(strategy=mock_strategy) pipeline_api.update_profile_from_edx( backend, student, {}, False, **{'edx_profile': self.mocked_edx_profile}) mock_strategy.session_set.assert_called_with('next', next_url)
def test_limit_members(self): self.login_admin() UserFactory.create_batch(3, accounts=[self.account]) url = reverse('member_create', kwargs={'url': get_current_account(self).url}) data = { 'first_name': lorem_ipsum.words(1, False).capitalize()[:50], 'last_name': lorem_ipsum.words(1, False).capitalize()[:50], 'email': self.user.email, 'password': User.objects.make_random_password(), 'date_joined_board': '{:%b. %d, %Y}'.format(timezone.now()), 'timezone': us_timezones[0], 'account': get_current_account(self), 'role': Membership.ROLES.member, 'invitation': True } response = self.client.post(url, data, follow=True) self.assertEqual(response.status_code, 200) self.assertContains( response, _('Limit of members amount for your billing plan is exceeded, ' 'you can upgrade it in your profile!'))
def setUpTestData(cls): cls.account = TradingAccountFactory(platform_type="mt4", group_name="demostd_test") cls.account.save() from profiles.factories import UserFactory user = UserFactory() user.set_password("test") user.save() cls.client = APIClient() cls.client.login(login=user.username, password='******')
def test_save_and_log_model(self): """ Tests that the save_model() function on OrderAdmin creates an OrderAudit entry """ assert OrderAudit.objects.count() == 0 order = OrderFactory.create() admin = OrderAdmin(model=order, admin_site=Mock()) mock_request = Mock(user=UserFactory.create()) admin.save_model( request=mock_request, obj=admin.model, form=Mock(), change=Mock() ) assert OrderAudit.objects.count() == 1
def test_update_wrong(self): user = UserFactory(accounts=[self.account]) self.login_member(user.email) url = reverse('news:edit', kwargs={ 'pk': self.news.pk, 'url': get_current_account(self).url }) data = { 'title': lorem_ipsum.words(2, False), 'text': lorem_ipsum.words(5, True), 'is_publish': True } response = self.client.post(url, data, follow=True) self.assertEqual(response.status_code, 403)
def test_add_channel(settings, mock_staff_client, mocker, patched_users_api): """add_channel should tell open-discussions to create a channel""" mock_staff_client.channels.create.return_value.ok = True settings.FEATURES['OPEN_DISCUSSIONS_USER_UPDATE'] = True title = "title" name = "name" description = "description" channel_type = "private" input_search = Search.from_dict({"unmodified": "search"}) modified_search = Search.from_dict({"result": "modified"}) adjust_search_for_percolator_stub = mocker.patch( 'discussions.api.adjust_search_for_percolator', autospec=True, return_value=modified_search, ) program = ProgramFactory.create() contributors = [UserFactory.create() for _ in range(5)] for user in contributors: ProgramEnrollmentFactory.create(user=user, program=program) populate_memberships_task_stub = mocker.patch('search.api.populate_query_memberships', autospec=True) add_moderators_task_stub = mocker.patch('discussions.api.add_moderators_to_channel', autospec=True) add_subscriber_stub = mocker.patch('discussions.api.add_subscriber_to_channel', autospec=True) add_moderator_stub = mocker.patch('discussions.api.add_moderator_to_channel', autospec=True) mod = UserFactory.create() channel = api.add_channel( original_search=input_search, title=title, name=name, description=description, channel_type=channel_type, program_id=program.id, creator_id=mod.id, ) mock_staff_client.channels.create.assert_called_once_with( title=title, name=name, description=description, channel_type=channel_type, ) adjust_search_for_percolator_stub.assert_called_once_with(input_search) assert channel.name == name query = channel.query assert query.source_type == PercolateQuery.DISCUSSION_CHANNEL_TYPE assert query.original_query == input_search.to_dict() assert query.query == modified_search.to_dict() assert ChannelProgram.objects.count() == 1 channel_program = ChannelProgram.objects.first() assert channel_program.program == program assert channel_program.channel == channel populate_memberships_task_stub.assert_called_once_with(query.id) add_moderators_task_stub.assert_called_once_with(channel.name) add_subscriber_stub.assert_called_once_with(channel.name, mod.discussion_user.username) add_moderator_stub.assert_called_once_with(channel.name, mod.discussion_user.username) _, updated_stub = patched_users_api updated_stub.assert_any_call(mod.discussion_user, allow_email_optin=False)
def test_sync_channel_memberships_api_error(mocker, patched_users_api): """ sync_user_to_channels should not fail hard on a sync exception """ user = UserFactory.create() # member here means the user matches the percolate query of the channel channels_to_add = [ChannelFactory.create() for _ in range(4)] channels_to_remove = [ChannelFactory.create() for _ in range(3)] programs = [ ChannelProgramFactory.create(channel=channel).program for channel in (channels_to_add + channels_to_remove) ] memberships_to_add = [ PercolateQueryMembership.objects.create(user=user, query=channel.query, needs_update=True, is_member=True) for channel in channels_to_add ] memberships_to_remove = [ PercolateQueryMembership.objects.create(user=user, query=channel.query, needs_update=True, is_member=False) for channel in channels_to_remove ] # Enroll the user in all programs. This isn't technically required but it's unrealistic to have a query # matching a user if they are not enrolled in the program. for program in programs: ProgramEnrollmentFactory.create(program=program, user=user) # One percolate query per channel assert PercolateQuery.objects.count() == len(channels_to_add) + len(channels_to_remove) # these are the first calls to be made for either change add_contributor_stub = mocker.patch( 'discussions.api.add_contributor_to_channel', autospec=True, side_effect=DiscussionUserSyncException ) remove_subscriber_stub = mocker.patch( 'discussions.api.remove_subscriber_from_channel', autospec=True, side_effect=DiscussionUserSyncException ) api.sync_channel_memberships(api.get_membership_ids_needing_sync()) created_stub, _ = patched_users_api created_stub.assert_any_call(user.discussion_user) assert add_contributor_stub.call_count == len(channels_to_add) assert remove_subscriber_stub.call_count == len(channels_to_remove) # should still need updates since everything failed for membership in memberships_to_add + memberships_to_remove: membership.refresh_from_db() assert membership.needs_update is True for channel in channels_to_add: add_contributor_stub.assert_any_call(channel.name, user.discussion_user.username) for channel in channels_to_remove: remove_subscriber_stub.assert_any_call(channel.name, user.discussion_user.username)
def test_sync_channel_memberships(mocker, patched_users_api): """ sync_user_to_channels should add or remove the user's membership from channels, not touching channels where the user is a moderator of at least one program """ user = UserFactory.create() # member here means the user matches the percolate query of the channel member_channels = [ChannelFactory.create() for _ in range(4)] nonmember_channels = [ChannelFactory.create() for _ in range(3)] # first channel of members and first channel of nonmembers are skipped since user is staff channels_to_add = member_channels[1:] channels_to_remove = nonmember_channels[1:] # User is a staff of some channels and not of others. # Note that a staff user may or may not match the percolate query or a channel staff_programs = [ ChannelProgramFactory.create(channel=member_channels[0]).program, ChannelProgramFactory.create(channel=nonmember_channels[0]).program, ] non_staff_programs = [ ChannelProgramFactory.create(channel=channel).program for channel in (channels_to_add + channels_to_remove) ] memberships_to_add = [ PercolateQueryMembership.objects.create(user=user, query=channel.query, needs_update=True, is_member=True) for channel in member_channels ] memberships_to_remove = [ PercolateQueryMembership.objects.create(user=user, query=channel.query, needs_update=True, is_member=False) for channel in nonmember_channels ] for program in staff_programs: with mute_signals(post_save): RoleFactory.create(program=program, user=user, role=Staff.ROLE_ID) # Enroll the user in all programs. This isn't technically required but it's unrealistic to have a query # matching a user if they are not enrolled in the program. for program in staff_programs + non_staff_programs: ProgramEnrollmentFactory.create(program=program, user=user) # One percolate query per channel assert PercolateQuery.objects.count() == len(member_channels) + len(nonmember_channels) add_subscriber_stub = mocker.patch( 'discussions.api.add_subscriber_to_channel', autospec=True, ) add_contributor_stub = mocker.patch( 'discussions.api.add_contributor_to_channel', autospec=True, ) remove_subscriber_stub = mocker.patch( 'discussions.api.remove_subscriber_from_channel', autospec=True, ) remove_contributor_stub = mocker.patch( 'discussions.api.remove_contributor_from_channel', autospec=True, ) api.sync_channel_memberships(api.get_membership_ids_needing_sync()) created_stub, _ = patched_users_api created_stub.assert_any_call(user.discussion_user) assert add_subscriber_stub.call_count == len(channels_to_add) assert add_contributor_stub.call_count == len(channels_to_add) assert remove_subscriber_stub.call_count == len(channels_to_remove) assert remove_contributor_stub.call_count == len(channels_to_remove) for membership in memberships_to_add + memberships_to_remove: membership.refresh_from_db() assert membership.needs_update is False for channel in channels_to_add: add_subscriber_stub.assert_any_call(channel.name, user.discussion_user.username) add_contributor_stub.assert_any_call(channel.name, user.discussion_user.username) for channel in channels_to_remove: remove_contributor_stub.assert_any_call(channel.name, user.discussion_user.username) remove_subscriber_stub.assert_any_call(channel.name, user.discussion_user.username)