Merge pull request #9607 from edx/diana/teams-event-tracking
Add teams eventing and tests.
This commit is contained in:
@@ -11,7 +11,7 @@ from flaky import flaky
|
||||
from nose.plugins.attrib import attr
|
||||
from uuid import uuid4
|
||||
|
||||
from ..helpers import UniqueCourseTest
|
||||
from ..helpers import UniqueCourseTest, EventsTestMixin
|
||||
from ...fixtures import LMS_BASE_URL
|
||||
from ...fixtures.course import CourseFixture
|
||||
from ...fixtures.discussion import (
|
||||
@@ -28,7 +28,7 @@ from ...pages.lms.teams import TeamsPage, MyTeamsPage, BrowseTopicsPage, BrowseT
|
||||
TOPICS_PER_PAGE = 12
|
||||
|
||||
|
||||
class TeamsTabBase(UniqueCourseTest):
|
||||
class TeamsTabBase(EventsTestMixin, UniqueCourseTest):
|
||||
"""Base class for Teams Tab tests"""
|
||||
def setUp(self):
|
||||
super(TeamsTabBase, self).setUp()
|
||||
@@ -123,6 +123,10 @@ class TeamsTabBase(UniqueCourseTest):
|
||||
# We are doing these operations on this top-level page object to avoid reloading the page.
|
||||
self.teams_page.verify_my_team_count(expected_number_of_teams)
|
||||
|
||||
def only_team_events(self, event):
|
||||
"""Filter out all non-team events."""
|
||||
return event['event_type'].startswith('edx.team.')
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@attr('shard_5')
|
||||
@@ -899,7 +903,8 @@ class CreateTeamTest(TeamFormActions):
|
||||
Then I should see the Create Team header and form
|
||||
When I fill all the fields present with appropriate data
|
||||
And I click Create button
|
||||
Then I should see the page for my team
|
||||
Then I expect analytics events to be emitted
|
||||
And I should see the page for my team
|
||||
And I should see the message that says "You are member of this team"
|
||||
And the new team should be added to the list of teams within the topic
|
||||
And the number of teams should be updated on the topic card
|
||||
@@ -911,7 +916,24 @@ class CreateTeamTest(TeamFormActions):
|
||||
self.verify_and_navigate_to_create_team_page()
|
||||
|
||||
self.fill_create_or_edit_form()
|
||||
self.create_or_edit_team_page.submit_form()
|
||||
|
||||
expected_events = [
|
||||
{
|
||||
'event_type': 'edx.team.created',
|
||||
'event': {
|
||||
'course_id': self.course_id,
|
||||
}
|
||||
},
|
||||
{
|
||||
'event_type': 'edx.team.learner_added',
|
||||
'event': {
|
||||
'course_id': self.course_id,
|
||||
'add_method': 'added_on_create',
|
||||
}
|
||||
}
|
||||
]
|
||||
with self.assert_events_match_during(event_filter=self.only_team_events, expected_events=expected_events):
|
||||
self.create_or_edit_team_page.submit_form()
|
||||
|
||||
# Verify that the page is shown for the new team
|
||||
team_page = TeamPage(self.browser, self.course_id)
|
||||
@@ -1330,6 +1352,7 @@ class TeamPageTest(TeamsTabBase):
|
||||
And I should not see New Post button
|
||||
When I click on Join Team button
|
||||
Then there should be no Join Team button and no message
|
||||
And an analytics event should be emitted
|
||||
And I should see the updated information under Team Details
|
||||
And I should see New Post button
|
||||
And if I switch to "My Team", the team I have joined is displayed
|
||||
@@ -1337,7 +1360,17 @@ class TeamPageTest(TeamsTabBase):
|
||||
self._set_team_configuration_and_membership(create_membership=False)
|
||||
self.team_page.visit()
|
||||
self.assertTrue(self.team_page.join_team_button_present)
|
||||
self.team_page.click_join_team_button()
|
||||
expected_events = [
|
||||
{
|
||||
'event_type': 'edx.team.learner_added',
|
||||
'event': {
|
||||
'course_id': self.course_id,
|
||||
'add_method': 'joined_from_team_view'
|
||||
}
|
||||
}
|
||||
]
|
||||
with self.assert_events_match_during(event_filter=self.only_team_events, expected_events=expected_events):
|
||||
self.team_page.click_join_team_button()
|
||||
self.assertFalse(self.team_page.join_team_button_present)
|
||||
self.assertFalse(self.team_page.join_team_message_present)
|
||||
self.assert_team_details(num_members=1, is_member=True)
|
||||
@@ -1397,6 +1430,7 @@ class TeamPageTest(TeamsTabBase):
|
||||
Then I should see Leave Team link
|
||||
When I click on Leave Team link
|
||||
Then user should be removed from team
|
||||
And an analytics event should be emitted
|
||||
And I should see Join Team button
|
||||
And I should not see New Post button
|
||||
And if I switch to "My Team", the team I have left is not displayed
|
||||
@@ -1405,7 +1439,17 @@ class TeamPageTest(TeamsTabBase):
|
||||
self.team_page.visit()
|
||||
self.assertFalse(self.team_page.join_team_button_present)
|
||||
self.assert_team_details(num_members=1)
|
||||
self.team_page.click_leave_team_link()
|
||||
expected_events = [
|
||||
{
|
||||
'event_type': 'edx.team.learner_removed',
|
||||
'event': {
|
||||
'course_id': self.course_id,
|
||||
'remove_method': 'self_removal'
|
||||
}
|
||||
}
|
||||
]
|
||||
with self.assert_events_match_during(event_filter=self.only_team_events, expected_events=expected_events):
|
||||
self.team_page.click_leave_team_link()
|
||||
self.assert_team_details(num_members=0, is_member=False)
|
||||
self.assertTrue(self.team_page.join_team_button_present)
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ from rest_framework.test import APITestCase, APIClient
|
||||
|
||||
from courseware.tests.factories import StaffFactory
|
||||
from common.test.utils import skip_signal
|
||||
from util.testing import EventTestMixin
|
||||
from student.tests.factories import UserFactory, AdminFactory, CourseEnrollmentFactory
|
||||
from student.models import CourseEnrollment
|
||||
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
|
||||
@@ -529,9 +530,12 @@ class TestListTeamsAPI(TeamAPITestCase):
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class TestCreateTeamAPI(TeamAPITestCase):
|
||||
class TestCreateTeamAPI(EventTestMixin, TeamAPITestCase):
|
||||
"""Test cases for the team creation endpoint."""
|
||||
|
||||
def setUp(self): # pylint: disable=arguments-differ
|
||||
super(TestCreateTeamAPI, self).setUp('teams.views.tracker')
|
||||
|
||||
@ddt.data(
|
||||
(None, 401),
|
||||
('student_inactive', 401),
|
||||
@@ -549,11 +553,15 @@ class TestCreateTeamAPI(TeamAPITestCase):
|
||||
teams = self.get_teams_list(user=user)
|
||||
self.assertIn("New Team", [team['name'] for team in teams['results']])
|
||||
|
||||
def _expected_team_id(self, team, expected_prefix):
|
||||
""" Return the team id that we'd expect given this team data and this prefix. """
|
||||
return expected_prefix + '-' + team['discussion_topic_id']
|
||||
|
||||
def verify_expected_team_id(self, team, expected_prefix):
|
||||
""" Verifies that the team id starts with the specified prefix and ends with the discussion_topic_id """
|
||||
self.assertIn('id', team)
|
||||
self.assertIn('discussion_topic_id', team)
|
||||
self.assertEqual(team['id'], expected_prefix + '-' + team['discussion_topic_id'])
|
||||
self.assertEqual(team['id'], self._expected_team_id(team, expected_prefix))
|
||||
|
||||
def test_naming(self):
|
||||
new_teams = [
|
||||
@@ -640,6 +648,19 @@ class TestCreateTeamAPI(TeamAPITestCase):
|
||||
self.verify_expected_team_id(team, 'fully-specified-team')
|
||||
del team['id']
|
||||
|
||||
self.assert_event_emitted(
|
||||
'edx.team.created',
|
||||
team_id=self._expected_team_id(team, 'fully-specified-team'),
|
||||
course_id=unicode(self.test_course_1.id),
|
||||
)
|
||||
|
||||
self.assert_event_emitted(
|
||||
'edx.team.learner_added',
|
||||
team_id=self._expected_team_id(team, 'fully-specified-team'),
|
||||
course_id=unicode(self.test_course_1.id),
|
||||
user_id=self.users[creator].id,
|
||||
add_method='added_on_create'
|
||||
)
|
||||
# Remove date_created and discussion_topic_id because they change between test runs
|
||||
del team['date_created']
|
||||
del team['discussion_topic_id']
|
||||
@@ -1026,9 +1047,12 @@ class TestListMembershipAPI(TeamAPITestCase):
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class TestCreateMembershipAPI(TeamAPITestCase):
|
||||
class TestCreateMembershipAPI(EventTestMixin, TeamAPITestCase):
|
||||
"""Test cases for the membership creation endpoint."""
|
||||
|
||||
def setUp(self): # pylint: disable=arguments-differ
|
||||
super(TestCreateMembershipAPI, self).setUp('teams.views.tracker')
|
||||
|
||||
@ddt.data(
|
||||
(None, 401),
|
||||
('student_inactive', 401),
|
||||
@@ -1053,6 +1077,18 @@ class TestCreateMembershipAPI(TeamAPITestCase):
|
||||
memberships = self.get_membership_list(200, {'team_id': self.solar_team.team_id})
|
||||
self.assertEqual(memberships['count'], 2)
|
||||
|
||||
add_method = 'joined_from_team_view' if user == 'student_enrolled_not_on_team' else 'added_by_another_user'
|
||||
|
||||
self.assert_event_emitted(
|
||||
'edx.team.learner_added',
|
||||
team_id=self.solar_team.team_id,
|
||||
user_id=self.users['student_enrolled_not_on_team'].id,
|
||||
course_id=unicode(self.solar_team.course_id),
|
||||
add_method=add_method
|
||||
)
|
||||
else:
|
||||
self.assert_no_events_were_emitted()
|
||||
|
||||
def test_no_username(self):
|
||||
response = self.post_create_membership(400, {'team_id': self.solar_team.team_id})
|
||||
self.assertIn('username', json.loads(response.content)['field_errors'])
|
||||
@@ -1176,9 +1212,12 @@ class TestDetailMembershipAPI(TeamAPITestCase):
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class TestDeleteMembershipAPI(TeamAPITestCase):
|
||||
class TestDeleteMembershipAPI(EventTestMixin, TeamAPITestCase):
|
||||
"""Test cases for the membership deletion endpoint."""
|
||||
|
||||
def setUp(self): # pylint: disable=arguments-differ
|
||||
super(TestDeleteMembershipAPI, self).setUp('teams.views.tracker')
|
||||
|
||||
@ddt.data(
|
||||
(None, 401),
|
||||
('student_inactive', 401),
|
||||
@@ -1198,6 +1237,18 @@ class TestDeleteMembershipAPI(TeamAPITestCase):
|
||||
user=user
|
||||
)
|
||||
|
||||
if status == 204:
|
||||
remove_method = 'self_removal' if user == 'student_enrolled' else 'removed_by_admin'
|
||||
self.assert_event_emitted(
|
||||
'edx.team.learner_removed',
|
||||
team_id=self.solar_team.team_id,
|
||||
course_id=unicode(self.solar_team.course_id),
|
||||
user_id=self.users['student_enrolled'].id,
|
||||
remove_method=remove_method
|
||||
)
|
||||
else:
|
||||
self.assert_no_events_were_emitted()
|
||||
|
||||
def test_bad_team(self):
|
||||
self.delete_membership('no_such_team', self.users['student_enrolled'].username, 404)
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ from xmodule.modulestore.django import modulestore
|
||||
from opaque_keys import InvalidKeyError
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
|
||||
from eventtracking import tracker
|
||||
from courseware.courses import get_course_with_access, has_access
|
||||
from student.models import CourseEnrollment, CourseAccessRole
|
||||
from student.roles import CourseStaffRole
|
||||
@@ -417,9 +418,22 @@ class TeamsListView(ExpandableFieldViewMixin, GenericAPIView):
|
||||
}, status=status.HTTP_400_BAD_REQUEST)
|
||||
else:
|
||||
team = serializer.save()
|
||||
tracker.emit('edx.team.created', {
|
||||
'team_id': team.team_id,
|
||||
'course_id': unicode(course_id)
|
||||
})
|
||||
if not team_administrator:
|
||||
# Add the creating user to the team.
|
||||
team.add_user(request.user)
|
||||
tracker.emit(
|
||||
'edx.team.learner_added',
|
||||
{
|
||||
'team_id': team.team_id,
|
||||
'user_id': request.user.id,
|
||||
'course_id': unicode(team.course_id),
|
||||
'add_method': 'added_on_create'
|
||||
}
|
||||
)
|
||||
return Response(CourseTeamSerializer(team).data)
|
||||
|
||||
def get_page(self):
|
||||
@@ -974,6 +988,15 @@ class MembershipListView(ExpandableFieldViewMixin, GenericAPIView):
|
||||
|
||||
try:
|
||||
membership = team.add_user(user)
|
||||
tracker.emit(
|
||||
'edx.team.learner_added',
|
||||
{
|
||||
'team_id': team.team_id,
|
||||
'user_id': user.id,
|
||||
'course_id': unicode(team.course_id),
|
||||
'add_method': 'joined_from_team_view' if user == request.user else 'added_by_another_user'
|
||||
}
|
||||
)
|
||||
except AlreadyOnTeamInCourse:
|
||||
return Response(
|
||||
build_api_error(
|
||||
@@ -1100,6 +1123,15 @@ class MembershipDetailView(ExpandableFieldViewMixin, GenericAPIView):
|
||||
if has_team_api_access(request.user, team.course_id, access_username=username):
|
||||
membership = self.get_membership(username, team)
|
||||
membership.delete()
|
||||
tracker.emit(
|
||||
'edx.team.learner_removed',
|
||||
{
|
||||
'team_id': team.team_id,
|
||||
'course_id': unicode(team.course_id),
|
||||
'user_id': membership.user.id,
|
||||
'remove_method': 'self_removal' if membership.user == request.user else 'removed_by_admin'
|
||||
}
|
||||
)
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
else:
|
||||
return Response(status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
Reference in New Issue
Block a user