create table that excludes enrollments from FBE

This commit is contained in:
Matthew Piatetsky
2019-10-29 11:29:03 -04:00
parent 5bf2a25842
commit c2774083ea
14 changed files with 84 additions and 40 deletions

View File

@@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.25 on 2019-10-31 14:49
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('student', '0023_bulkunenrollconfiguration'),
]
operations = [
migrations.CreateModel(
name='FBEEnrollmentExclusion',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('enrollment', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='student.CourseEnrollment')),
],
),
]

View File

@@ -2045,6 +2045,22 @@ class CourseEnrollment(models.Model):
cache[(user_id, course_key)] = enrollment_state
@python_2_unicode_compatible
class FBEEnrollmentExclusion(models.Model):
"""
Disable FBE for enrollments in this table.
.. no_pii:
"""
enrollment = models.ForeignKey(
CourseEnrollment,
on_delete=models.DO_NOTHING,
)
def __str__(self):
return "[FBEEnrollmentExclusion] %s" % (self.enrollment,)
@receiver(models.signals.post_save, sender=CourseEnrollment)
@receiver(models.signals.post_delete, sender=CourseEnrollment)
def invalidate_enrollment_mode_cache(sender, instance, **kwargs): # pylint: disable=unused-argument, invalid-name

View File

@@ -244,7 +244,7 @@ class TestFieldOverrideMongoPerformance(FieldOverridePerformanceTestCase):
__test__ = True
# TODO: decrease query count as part of REVO-28
QUERY_COUNT = 36
QUERY_COUNT = 40
TEST_DATA = {
# (providers, course_width, enable_ccx, view_as_ccx): (
# # of sql queries to default,
@@ -273,7 +273,7 @@ class TestFieldOverrideSplitPerformance(FieldOverridePerformanceTestCase):
__test__ = True
# TODO: decrease query count as part of REVO-28
QUERY_COUNT = 36
QUERY_COUNT = 40
TEST_DATA = {
('no_overrides', 1, True, False): (QUERY_COUNT, 3),

View File

@@ -225,8 +225,8 @@ class IndexQueryTestCase(ModuleStoreTestCase):
NUM_PROBLEMS = 20
@ddt.data(
(ModuleStoreEnum.Type.mongo, 10, 186),
(ModuleStoreEnum.Type.split, 4, 180),
(ModuleStoreEnum.Type.mongo, 10, 193),
(ModuleStoreEnum.Type.split, 4, 185),
)
@ddt.unpack
def test_index_query_counts(self, store_type, expected_mongo_query_count, expected_mysql_query_count):
@@ -1459,8 +1459,8 @@ class ProgressPageTests(ProgressPageBaseTests):
self.assertContains(resp, u"Download Your Certificate")
@ddt.data(
(True, 56),
(False, 55)
(True, 60),
(False, 59)
)
@ddt.unpack
def test_progress_queries_paced_courses(self, self_paced, query_count):
@@ -1473,8 +1473,8 @@ class ProgressPageTests(ProgressPageBaseTests):
@patch.dict(settings.FEATURES, {'ASSUME_ZERO_GRADE_IF_ABSENT_FOR_ALL_TESTS': False})
@ddt.data(
(False, 64, 44),
(True, 55, 39)
(False, 68, 48),
(True, 59, 43)
)
@ddt.unpack
def test_progress_queries(self, enable_waffle, initial, subsequent):

View File

@@ -404,8 +404,8 @@ class ViewsQueryCountTestCase(
return inner
@ddt.data(
(ModuleStoreEnum.Type.mongo, 3, 4, 41),
(ModuleStoreEnum.Type.split, 3, 13, 41),
(ModuleStoreEnum.Type.mongo, 3, 4, 42),
(ModuleStoreEnum.Type.split, 3, 13, 42),
)
@ddt.unpack
@count_queries
@@ -413,8 +413,8 @@ class ViewsQueryCountTestCase(
self.create_thread_helper(mock_request)
@ddt.data(
(ModuleStoreEnum.Type.mongo, 3, 3, 37),
(ModuleStoreEnum.Type.split, 3, 10, 37),
(ModuleStoreEnum.Type.mongo, 3, 3, 38),
(ModuleStoreEnum.Type.split, 3, 10, 38),
)
@ddt.unpack
@count_queries

View File

@@ -464,18 +464,18 @@ class SingleThreadQueryCountTestCase(ForumsEnableMixin, ModuleStoreTestCase):
# course is outside the context manager that is verifying the number of queries,
# and with split mongo, that method ends up querying disabled_xblocks (which is then
# cached and hence not queried as part of call_single_thread).
(ModuleStoreEnum.Type.mongo, False, 1, 5, 2, 24, 9),
(ModuleStoreEnum.Type.mongo, False, 50, 5, 2, 24, 9),
(ModuleStoreEnum.Type.mongo, False, 1, 5, 2, 25, 10),
(ModuleStoreEnum.Type.mongo, False, 50, 5, 2, 25, 10),
# split mongo: 3 queries, regardless of thread response size.
(ModuleStoreEnum.Type.split, False, 1, 3, 3, 24, 9),
(ModuleStoreEnum.Type.split, False, 50, 3, 3, 24, 9),
(ModuleStoreEnum.Type.split, False, 1, 3, 3, 25, 10),
(ModuleStoreEnum.Type.split, False, 50, 3, 3, 25, 10),
# Enabling Enterprise integration should have no effect on the number of mongo queries made.
(ModuleStoreEnum.Type.mongo, True, 1, 5, 2, 24, 9),
(ModuleStoreEnum.Type.mongo, True, 50, 5, 2, 24, 9),
(ModuleStoreEnum.Type.mongo, True, 1, 5, 2, 25, 10),
(ModuleStoreEnum.Type.mongo, True, 50, 5, 2, 25, 10),
# split mongo: 3 queries, regardless of thread response size.
(ModuleStoreEnum.Type.split, True, 1, 3, 3, 24, 9),
(ModuleStoreEnum.Type.split, True, 50, 3, 3, 24, 9),
(ModuleStoreEnum.Type.split, True, 1, 3, 3, 25, 10),
(ModuleStoreEnum.Type.split, True, 50, 3, 3, 25, 10),
)
@ddt.unpack
def test_number_of_mongo_queries(

View File

@@ -97,35 +97,35 @@ class TestCourseGradeFactory(GradeTestBase):
[self.sequence.display_name, self.sequence2.display_name]
)
with self.assertNumQueries(4), mock_get_score(1, 2):
with self.assertNumQueries(5), mock_get_score(1, 2):
_assert_read(expected_pass=False, expected_percent=0) # start off with grade of 0
num_queries = 47
num_queries = 48
with self.assertNumQueries(num_queries), mock_get_score(1, 2):
grade_factory.update(self.request.user, self.course, force_update_subsections=True)
with self.assertNumQueries(5):
with self.assertNumQueries(6):
_assert_read(expected_pass=True, expected_percent=0.5) # updated to grade of .5
num_queries = 9
num_queries = 10
with self.assertNumQueries(num_queries), mock_get_score(1, 4):
grade_factory.update(self.request.user, self.course, force_update_subsections=False)
with self.assertNumQueries(5):
with self.assertNumQueries(6):
_assert_read(expected_pass=True, expected_percent=0.5) # NOT updated to grade of .25
num_queries = 26
num_queries = 27
with self.assertNumQueries(num_queries), mock_get_score(2, 2):
grade_factory.update(self.request.user, self.course, force_update_subsections=True)
with self.assertNumQueries(5):
with self.assertNumQueries(6):
_assert_read(expected_pass=True, expected_percent=1.0) # updated to grade of 1.0
num_queries = 30
num_queries = 31
with self.assertNumQueries(num_queries), mock_get_score(0, 0): # the subsection now is worth zero
grade_factory.update(self.request.user, self.course, force_update_subsections=True)
with self.assertNumQueries(5):
with self.assertNumQueries(6):
_assert_read(expected_pass=False, expected_percent=0.0) # updated to grade of 0.0
@patch.dict(settings.FEATURES, {'ASSUME_ZERO_GRADE_IF_ABSENT_FOR_ALL_TESTS': False})

View File

@@ -3,9 +3,10 @@ from __future__ import absolute_import
from experiments.models import ExperimentData
from openedx.features.course_duration_limits.config import EXPERIMENT_DATA_HOLDBACK_KEY, EXPERIMENT_ID
from student.models import FBEEnrollmentExclusion
def is_in_holdback(user):
def is_in_holdback(user, enrollment):
"""
Return true if given user is in holdback expermiment
"""
@@ -21,4 +22,8 @@ def is_in_holdback(user):
except ExperimentData.DoesNotExist:
pass
if enrollment is not None:
if FBEEnrollmentExclusion.objects.filter(enrollment=enrollment).exists():
return True
return in_holdback

View File

@@ -134,7 +134,7 @@ class ContentTypeGatingConfig(StackedConfigurationModel):
return False
# check if user is in holdback
if user_variable_represents_correct_user and is_in_holdback(user):
if user_variable_represents_correct_user and is_in_holdback(user, enrollment):
return False
if not correct_modes_for_fbe(course_key, enrollment, user):

View File

@@ -78,9 +78,9 @@ class TestContentTypeGatingConfig(CacheIsolationTestCase):
user = self.user
course_key = self.course_overview.id
query_count = 7
if not already_enrolled or not pass_enrollment and already_enrolled:
query_count = 8
query_count = 8
if not already_enrolled and pass_enrollment or not pass_enrollment and already_enrolled:
query_count = 9
with self.assertNumQueries(query_count):
enabled = ContentTypeGatingConfig.enabled_for_enrollment(

View File

@@ -128,7 +128,7 @@ class CourseDurationLimitConfig(StackedConfigurationModel):
student_masquerade = is_masquerading_as_specific_student(user, course_key)
# check if user is in holdback
if (no_masquerade or student_masquerade) and is_in_holdback(user):
if (no_masquerade or student_masquerade) and is_in_holdback(user, enrollment):
return False
not_student_masquerade = is_masquerading and not student_masquerade

View File

@@ -84,9 +84,9 @@ class TestCourseDurationLimitConfig(CacheIsolationTestCase):
user = self.user
course_key = self.course_overview.id
query_count = 7
if pass_enrollment and already_enrolled:
query_count = 6
query_count = 8
if pass_enrollment and already_enrolled or not pass_enrollment and not already_enrolled:
query_count = 7
with self.assertNumQueries(query_count):
enabled = CourseDurationLimitConfig.enabled_for_enrollment(

View File

@@ -220,7 +220,7 @@ class TestCourseHomePage(CourseHomePageTestCase):
# Fetch the view and verify the query counts
# TODO: decrease query count as part of REVO-28
with self.assertNumQueries(97, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST):
with self.assertNumQueries(106, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST):
with check_mongo_calls(4):
url = course_home_url(self.course)
self.client.get(url)

View File

@@ -134,7 +134,7 @@ class TestCourseUpdatesPage(SharedModuleStoreTestCase):
# Fetch the view and verify that the query counts haven't changed
# TODO: decrease query count as part of REVO-28
with self.assertNumQueries(56, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST):
with self.assertNumQueries(59, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST):
with check_mongo_calls(4):
url = course_updates_url(self.course)
self.client.get(url)