From 85139452291014de34bbb11bbeaccc484c6ae948 Mon Sep 17 00:00:00 2001 From: Jeremy Bowman Date: Fri, 12 Jan 2018 16:31:03 -0500 Subject: [PATCH] PLAT-1831 Install prereqs for tox-based bok-choy and lettuce runs --- common/djangoapps/terrain/__init__.py | 14 +++++--- common/djangoapps/terrain/browser.py | 6 ++-- common/djangoapps/terrain/course_helpers.py | 16 ++++----- common/djangoapps/terrain/factories.py | 39 ++++++++++++--------- scripts/unit-tests.sh | 5 +++ tox.ini | 1 - 6 files changed, 49 insertions(+), 32 deletions(-) diff --git a/common/djangoapps/terrain/__init__.py b/common/djangoapps/terrain/__init__.py index a99980ec95..b769c8414c 100644 --- a/common/djangoapps/terrain/__init__.py +++ b/common/djangoapps/terrain/__init__.py @@ -2,7 +2,13 @@ # across all lms apps can be put in terrain/common # See https://groups.google.com/forum/?fromgroups=#!msg/lettuce-users/5VyU9B4HcX8/USgbGIJdS5QJ -from terrain.browser import * # pylint: disable=wildcard-import -from terrain.steps import * # pylint: disable=wildcard-import -from terrain.factories import * # pylint: disable=wildcard-import -from terrain.setup_prereqs import * # pylint: disable=wildcard-import +import lettuce +from django.utils.functional import SimpleLazyObject +from .browser import * # pylint: disable=wildcard-import +from .factories import absorb_factories +from .steps import * # pylint: disable=wildcard-import +from .setup_prereqs import * # pylint: disable=wildcard-import + +# Delay absorption of factories until the next access, +# after Django apps have finished initializing +setattr(lettuce, 'world', SimpleLazyObject(absorb_factories)) diff --git a/common/djangoapps/terrain/browser.py b/common/djangoapps/terrain/browser.py index 6c59c5da6e..455ba2cf25 100644 --- a/common/djangoapps/terrain/browser.py +++ b/common/djangoapps/terrain/browser.py @@ -17,7 +17,6 @@ from selenium.common.exceptions import WebDriverException from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from splinter.browser import Browser -import xmodule.modulestore.django from xmodule.contentstore.django import _CONTENTSTORE LOGGER = getLogger(__name__) @@ -178,11 +177,12 @@ def clear_data(scenario): @after.each_scenario def reset_databases(scenario): - ''' + """ After each scenario, all databases are cleared/dropped. Contentstore data are stored in unique databases whereas modulestore data is in unique collection names. This data is created implicitly during the scenarios. If no data is created during the test, these lines equivilently do nothing. - ''' + """ + import xmodule.modulestore.django xmodule.modulestore.django.modulestore()._drop_database() # pylint: disable=protected-access xmodule.modulestore.django.clear_existing_modulestores() _CONTENTSTORE.clear() diff --git a/common/djangoapps/terrain/course_helpers.py b/common/djangoapps/terrain/course_helpers.py index 92988f72d4..94457a44fd 100644 --- a/common/djangoapps/terrain/course_helpers.py +++ b/common/djangoapps/terrain/course_helpers.py @@ -2,19 +2,18 @@ import urllib -from django.contrib.auth.models import User +from django.apps import apps +from django.contrib.auth import get_user_model from lettuce import world -from student.models import CourseEnrollment from xmodule.contentstore.django import _CONTENTSTORE -from xmodule.modulestore.django import clear_existing_modulestores, modulestore @world.absorb def create_user(uname, password): # If the user already exists, don't try to create it again - if len(User.objects.filter(username=uname)) > 0: + if len(get_user_model().objects.filter(username=uname)) > 0: return portal_user = world.UserFactory.build(username=uname, email=uname + '@edx.org') @@ -39,20 +38,20 @@ def log_in(username='robot', password='test', email='robot@edx.org', name="Robot world.visit(url) # Save the user info in the world scenario_dict for use in the tests - user = User.objects.get(username=username) + user = get_user_model().objects.get(username=username) world.scenario_dict['USER'] = user @world.absorb def register_by_course_key(course_key, username='robot', password='test', is_staff=False): create_user(username, password) - user = User.objects.get(username=username) + user = get_user_model().objects.get(username=username) # Note: this flag makes the user global staff - that is, an edX employee - not a course staff. # See courseware.tests.factories for StaffFactory and InstructorFactory. if is_staff: user.is_staff = True user.save() - CourseEnrollment.enroll(user, course_key) + apps.get_model('student', 'CourseEnrollment').enroll(user, course_key) @world.absorb @@ -62,7 +61,7 @@ def enroll_user(user, course_key): registration.register(user) registration.activate() # Enroll them in the course - CourseEnrollment.enroll(user, course_key) + apps.get_model('student', 'CourseEnrollment').enroll(user, course_key) @world.absorb @@ -72,6 +71,7 @@ def clear_courses(): # (though it shouldn't), do this manually # from the bash shell to drop it: # $ mongo test_xmodule --eval "db.dropDatabase()" + from xmodule.modulestore.django import clear_existing_modulestores, modulestore modulestore()._drop_database() # pylint: disable=protected-access _CONTENTSTORE.clear() clear_existing_modulestores() diff --git a/common/djangoapps/terrain/factories.py b/common/djangoapps/terrain/factories.py index c8009277ef..8df3f354d8 100644 --- a/common/djangoapps/terrain/factories.py +++ b/common/djangoapps/terrain/factories.py @@ -1,23 +1,30 @@ -''' +""" Factories are defined in other modules and absorbed here into the lettuce world so that they can be used by both unit tests and integration / BDD tests. -''' +""" from lettuce import world -import course_modes.tests.factories as cmf -import student.tests.factories as sf -import xmodule.modulestore.tests.factories as xf -# Unlock XBlock factories, because we're randomizing the collection -# name above to prevent collisions -xf.XMODULE_FACTORY_LOCK.enable() +def absorb_factories(): + """ + Absorb the factories and return the resulting ``world`` object. + """ + import course_modes.tests.factories as cmf + import student.tests.factories as sf + import xmodule.modulestore.tests.factories as xf -world.absorb(sf.UserFactory) -world.absorb(sf.UserProfileFactory) -world.absorb(sf.RegistrationFactory) -world.absorb(sf.GroupFactory) -world.absorb(sf.CourseEnrollmentAllowedFactory) -world.absorb(cmf.CourseModeFactory) -world.absorb(xf.CourseFactory) -world.absorb(xf.ItemFactory) + # Unlock XBlock factories, because we're randomizing the collection + # name above to prevent collisions + xf.XMODULE_FACTORY_LOCK.enable() + + world.absorb(sf.UserFactory) + world.absorb(sf.UserProfileFactory) + world.absorb(sf.RegistrationFactory) + world.absorb(sf.GroupFactory) + world.absorb(sf.CourseEnrollmentAllowedFactory) + world.absorb(cmf.CourseModeFactory) + world.absorb(xf.CourseFactory) + world.absorb(xf.ItemFactory) + + return world diff --git a/scripts/unit-tests.sh b/scripts/unit-tests.sh index f4cb1164b7..79c9935faa 100755 --- a/scripts/unit-tests.sh +++ b/scripts/unit-tests.sh @@ -32,6 +32,11 @@ set -e PAVER_ARGS="-v" PARALLEL="--processes=-1" +# Skip re-installation of Python prerequisites inside a tox execution. +if [[ -n "$TOXENV" ]]; then + export NO_PREREQ_INSTALL="True" +fi + case "${TEST_SUITE}" in "lms-unit") diff --git a/tox.ini b/tox.ini index f52278750d..fdf56b545a 100644 --- a/tox.ini +++ b/tox.ini @@ -24,7 +24,6 @@ toxworkdir={homedir}/edxapp_toxenv usedevelop=True setenv = # Instruct paver not to install the packages tox just installed - NO_PREREQ_INSTALL=True PYTHONHASHSEED=0 TOXENV={envname} passenv =