Commit 3a772752 by Nimisha Asthagiri

LMS-11286 Paver Bokchoy support for Split; default store set to Split.

parent 1d9c272a
...@@ -567,7 +567,11 @@ def _create_new_course(request, org, number, run, fields): ...@@ -567,7 +567,11 @@ def _create_new_course(request, org, number, run, fields):
fields.update(definition_data) fields.update(definition_data)
store = modulestore() store = modulestore()
with store.default_store(settings.FEATURES.get('DEFAULT_STORE_FOR_NEW_COURSE', 'mongo')): store_for_new_course = (
settings.FEATURES.get('DEFAULT_STORE_FOR_NEW_COURSE') or
store.default_modulestore.get_modulestore_type()
)
with store.default_store(store_for_new_course):
# Creating the course raises DuplicateCourseError if an existing course with this org/name is found # Creating the course raises DuplicateCourseError if an existing course with this org/name is found
new_course = store.create_course( new_course = store.create_course(
org, org,
...@@ -584,7 +588,8 @@ def _create_new_course(request, org, number, run, fields): ...@@ -584,7 +588,8 @@ def _create_new_course(request, org, number, run, fields):
initialize_permissions(new_course.id, request.user) initialize_permissions(new_course.id, request.user)
return JsonResponse({ return JsonResponse({
'url': reverse_course_url('course_handler', new_course.id) 'url': reverse_course_url('course_handler', new_course.id),
'course_key': unicode(new_course.id),
}) })
......
...@@ -106,7 +106,7 @@ FEATURES = { ...@@ -106,7 +106,7 @@ FEATURES = {
'ADVANCED_SECURITY': False, 'ADVANCED_SECURITY': False,
# Modulestore to use for new courses # Modulestore to use for new courses
'DEFAULT_STORE_FOR_NEW_COURSE': 'mongo', 'DEFAULT_STORE_FOR_NEW_COURSE': None,
} }
ENABLE_JASMINE = False ENABLE_JASMINE = False
......
...@@ -11,6 +11,8 @@ from textwrap import dedent ...@@ -11,6 +11,8 @@ from textwrap import dedent
from collections import namedtuple from collections import namedtuple
from path import path from path import path
from lazy import lazy from lazy import lazy
from opaque_keys.edx.keys import CourseKey
from opaque_keys.edx.locator import CourseLocator
from . import STUDIO_BASE_URL from . import STUDIO_BASE_URL
...@@ -204,6 +206,7 @@ class CourseFixture(StudioApiFixture): ...@@ -204,6 +206,7 @@ class CourseFixture(StudioApiFixture):
self.children = [] self.children = []
self._assets = [] self._assets = []
self._advanced_settings = {} self._advanced_settings = {}
self._course_key = None
def __str__(self): def __str__(self):
""" """
...@@ -264,18 +267,12 @@ class CourseFixture(StudioApiFixture): ...@@ -264,18 +267,12 @@ class CourseFixture(StudioApiFixture):
return self return self
@property @property
def _course_key(self):
"""
Return the locator string for the course.
"""
return "{org}/{number}/{run}".format(**self._course_dict)
@property
def _course_location(self): def _course_location(self):
""" """
Return the locator string for the course. Return the locator string for the course.
""" """
return "i4x://{org}/{number}/course/{run}".format(**self._course_dict) course_key = CourseKey.from_string(self._course_key)
return unicode(course_key.make_usage_key('course', self._course_dict['run']))
@property @property
def _assets_url(self): def _assets_url(self):
...@@ -289,7 +286,8 @@ class CourseFixture(StudioApiFixture): ...@@ -289,7 +286,8 @@ class CourseFixture(StudioApiFixture):
""" """
Return the locator string for the course handouts Return the locator string for the course handouts
""" """
return "i4x://{org}/{number}/course_info/handouts".format(**self._course_dict) course_key = CourseKey.from_string(self._course_key)
return unicode(course_key.make_usage_key('course_info', 'handouts'))
def _create_course(self): def _create_course(self):
""" """
...@@ -315,7 +313,9 @@ class CourseFixture(StudioApiFixture): ...@@ -315,7 +313,9 @@ class CourseFixture(StudioApiFixture):
if err is not None: if err is not None:
raise CourseFixtureError("Could not create course {0}. Error message: '{1}'".format(self, err)) raise CourseFixtureError("Could not create course {0}. Error message: '{1}'".format(self, err))
if not response.ok: if response.ok:
self._course_key = response.json()['course_key']
else:
raise CourseFixtureError( raise CourseFixtureError(
"Could not create course {0}. Status was {1}".format( "Could not create course {0}. Status was {1}".format(
self._course_dict, response.status_code)) self._course_dict, response.status_code))
......
...@@ -5,8 +5,10 @@ import json ...@@ -5,8 +5,10 @@ import json
import unittest import unittest
import functools import functools
import requests import requests
import os
from path import path from path import path
from bok_choy.web_app_test import WebAppTest from bok_choy.web_app_test import WebAppTest
from opaque_keys.edx.locator import CourseLocator
def skip_if_browser(browser): def skip_if_browser(browser):
...@@ -170,8 +172,6 @@ class UniqueCourseTest(WebAppTest): ...@@ -170,8 +172,6 @@ class UniqueCourseTest(WebAppTest):
Test that provides a unique course ID. Test that provides a unique course ID.
""" """
COURSE_ID_SEPARATOR = "/"
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
""" """
Create a unique course ID. Create a unique course ID.
...@@ -190,11 +190,18 @@ class UniqueCourseTest(WebAppTest): ...@@ -190,11 +190,18 @@ class UniqueCourseTest(WebAppTest):
@property @property
def course_id(self): def course_id(self):
return self.COURSE_ID_SEPARATOR.join([ """
Returns the serialized course_key for the test
"""
# TODO - is there a better way to make this agnostic to the underlying default module store?
default_store = os.environ.get('DEFAULT_STORE', 'draft')
course_key = CourseLocator(
self.course_info['org'], self.course_info['org'],
self.course_info['number'], self.course_info['number'],
self.course_info['run'] self.course_info['run'],
]) deprecated=(default_store == 'draft')
)
return unicode(course_key)
class YouTubeConfigError(Exception): class YouTubeConfigError(Exception):
......
...@@ -274,6 +274,14 @@ To put a debugging breakpoint in a test use: ...@@ -274,6 +274,14 @@ To put a debugging breakpoint in a test use:
from nose.tools import set_trace; set_trace() from nose.tools import set_trace; set_trace()
By default, all bokchoy tests are run with the 'split' ModuleStore.
To override the modulestore that is used, use the default_store option. The currently supported stores are:
'split' (xmodule.modulestore.split_mongo.split_draft.DraftVersioningModuleStore) and
'draft' (xmodule.modulestore.mongo.DraftMongoModuleStore).
For example:
paver test_bokchoy --default_store='draft'
### Running Lettuce Acceptance Tests ### Running Lettuce Acceptance Tests
...@@ -309,6 +317,14 @@ To start the debugger on failure, add the `--pdb` option to extra_args: ...@@ -309,6 +317,14 @@ To start the debugger on failure, add the `--pdb` option to extra_args:
To run tests faster by not collecting static files, you can use To run tests faster by not collecting static files, you can use
`paver test_acceptance -s lms --fasttest` and `paver test_acceptance -s cms --fasttest`. `paver test_acceptance -s lms --fasttest` and `paver test_acceptance -s cms --fasttest`.
By default, all acceptance tests are run with the 'draft' ModuleStore.
To override the modulestore that is used, use the default_store option. Currently, the possible stores for acceptance tests are:
'split' (xmodule.modulestore.split_mongo.split_draft.DraftVersioningModuleStore) and
'draft' (xmodule.modulestore.mongo.DraftMongoModuleStore).
For example:
paver test_acceptance --default_store='draft'
Note, however, all acceptance tests currently do not pass with 'split'.
Acceptance tests will run on a randomized port and can be run in the background of paver cms and lms or unit tests. Acceptance tests will run on a randomized port and can be run in the background of paver cms and lms or unit tests.
To specify the port, change the LETTUCE_SERVER_PORT constant in cms/envs/acceptance.py and lms/envs/acceptance.py To specify the port, change the LETTUCE_SERVER_PORT constant in cms/envs/acceptance.py and lms/envs/acceptance.py
as well as the port listed in cms/djangoapps/contentstore/feature/upload.py as well as the port listed in cms/djangoapps/contentstore/feature/upload.py
......
...@@ -22,6 +22,7 @@ __test__ = False # do not collect ...@@ -22,6 +22,7 @@ __test__ = False # do not collect
('test_spec=', 't', 'Specific test to run'), ('test_spec=', 't', 'Specific test to run'),
('fasttest', 'a', 'Skip some setup'), ('fasttest', 'a', 'Skip some setup'),
('extra_args=', 'e', 'adds as extra args to the test command'), ('extra_args=', 'e', 'adds as extra args to the test command'),
('default_store=', 's', 'Default modulestore'),
make_option("--verbose", action="store_const", const=2, dest="verbosity"), make_option("--verbose", action="store_const", const=2, dest="verbosity"),
make_option("-q", "--quiet", action="store_const", const=0, dest="verbosity"), make_option("-q", "--quiet", action="store_const", const=0, dest="verbosity"),
make_option("-v", "--verbosity", action="count", dest="verbosity"), make_option("-v", "--verbosity", action="count", dest="verbosity"),
...@@ -45,13 +46,12 @@ def test_bokchoy(options): ...@@ -45,13 +46,12 @@ def test_bokchoy(options):
opts = { opts = {
'test_spec': getattr(options, 'test_spec', None), 'test_spec': getattr(options, 'test_spec', None),
'fasttest': getattr(options, 'fasttest', False), 'fasttest': getattr(options, 'fasttest', False),
'default_store': getattr(options, 'default_store', None),
'verbosity': getattr(options, 'verbosity', 2), 'verbosity': getattr(options, 'verbosity', 2),
'extra_args': getattr(options, 'extra_args', ''), 'extra_args': getattr(options, 'extra_args', ''),
'test_dir': 'tests', 'test_dir': 'tests',
} }
run_bokchoy(**opts)
test_suite = BokChoyTestSuite('bok-choy', **opts)
test_suite.run()
@task @task
...@@ -60,6 +60,7 @@ def test_bokchoy(options): ...@@ -60,6 +60,7 @@ def test_bokchoy(options):
('test_spec=', 't', 'Specific test to run'), ('test_spec=', 't', 'Specific test to run'),
('fasttest', 'a', 'Skip some setup'), ('fasttest', 'a', 'Skip some setup'),
('imports_dir=', 'd', 'Directory containing (un-archived) courses to be imported'), ('imports_dir=', 'd', 'Directory containing (un-archived) courses to be imported'),
('default_store=', 's', 'Default modulestore'),
make_option("--verbose", action="store_const", const=2, dest="verbosity"), make_option("--verbose", action="store_const", const=2, dest="verbosity"),
make_option("-q", "--quiet", action="store_const", const=0, dest="verbosity"), make_option("-q", "--quiet", action="store_const", const=0, dest="verbosity"),
make_option("-v", "--verbosity", action="count", dest="verbosity"), make_option("-v", "--verbosity", action="count", dest="verbosity"),
...@@ -72,13 +73,33 @@ def perf_report_bokchoy(options): ...@@ -72,13 +73,33 @@ def perf_report_bokchoy(options):
'test_spec': getattr(options, 'test_spec', None), 'test_spec': getattr(options, 'test_spec', None),
'fasttest': getattr(options, 'fasttest', False), 'fasttest': getattr(options, 'fasttest', False),
'imports_dir': getattr(options, 'imports_dir', None), 'imports_dir': getattr(options, 'imports_dir', None),
'default_store': getattr(options, 'default_store', None),
'verbosity': getattr(options, 'verbosity', 2), 'verbosity': getattr(options, 'verbosity', 2),
'test_dir': 'performance', 'test_dir': 'performance',
'ptests': True, 'ptests': True,
} }
run_bokchoy(**opts)
def run_bokchoy(**opts):
"""
Runs BokChoyTestSuite with the given options.
If a default store is not specified, runs the test suite for 'split' as the default store.
"""
if opts['default_store'] not in ['draft', 'split']:
msg = colorize(
'red',
'No modulestore specified, running tests for split.'
)
print(msg)
stores = ['split']
else:
stores = [opts['default_store']]
test_suite = BokChoyTestSuite('bok-choy', **opts) for store in stores:
test_suite.run() opts['default_store'] = store
test_suite = BokChoyTestSuite('bok-choy', **opts)
test_suite.run()
@task @task
......
...@@ -18,7 +18,7 @@ except ImportError: ...@@ -18,7 +18,7 @@ except ImportError:
__test__ = False # do not collect __test__ = False # do not collect
def start_servers(): def start_servers(default_store):
""" """
Start the servers we will run tests on, returns PIDs for servers. Start the servers we will run tests on, returns PIDs for servers.
""" """
...@@ -33,9 +33,11 @@ def start_servers(): ...@@ -33,9 +33,11 @@ def start_servers():
for service, info in Env.BOK_CHOY_SERVERS.iteritems(): for service, info in Env.BOK_CHOY_SERVERS.iteritems():
address = "0.0.0.0:{}".format(info['port']) address = "0.0.0.0:{}".format(info['port'])
cmd = ( cmd = (
"DEFAULT_STORE={default_store} "
"coverage run --rcfile={coveragerc} -m " "coverage run --rcfile={coveragerc} -m "
"manage {service} --settings bok_choy runserver " "manage {service} --settings bok_choy runserver "
"{address} --traceback --noreload".format( "{address} --traceback --noreload".format(
default_store=default_store,
coveragerc=Env.BOK_CHOY_COVERAGERC, coveragerc=Env.BOK_CHOY_COVERAGERC,
service=service, service=service,
address=address, address=address,
......
...@@ -28,6 +28,7 @@ class BokChoyTestSuite(TestSuite): ...@@ -28,6 +28,7 @@ class BokChoyTestSuite(TestSuite):
self.cache = Env.BOK_CHOY_CACHE self.cache = Env.BOK_CHOY_CACHE
self.fasttest = kwargs.get('fasttest', False) self.fasttest = kwargs.get('fasttest', False)
self.test_spec = kwargs.get('test_spec', None) self.test_spec = kwargs.get('test_spec', None)
self.default_store = kwargs.get('default_store')
self.verbosity = kwargs.get('verbosity', 2) self.verbosity = kwargs.get('verbosity', 2)
self.extra_args = kwargs.get('extra_args', '') self.extra_args = kwargs.get('extra_args', '')
self.ptests = kwargs.get('ptests', False) self.ptests = kwargs.get('ptests', False)
...@@ -64,17 +65,26 @@ class BokChoyTestSuite(TestSuite): ...@@ -64,17 +65,26 @@ class BokChoyTestSuite(TestSuite):
self.cache.flush_all() self.cache.flush_all()
sh( sh(
"./manage.py lms --settings bok_choy loaddata --traceback" "DEFAULT_STORE={default_store}"
" common/test/db_fixtures/*.json" " ./manage.py lms --settings bok_choy loaddata --traceback"
" common/test/db_fixtures/*.json".format(
default_store=self.default_store,
)
) )
if self.imports_dir: if self.imports_dir:
sh("./manage.py cms --settings=bok_choy import {}".format(self.imports_dir)) sh(
"DEFAULT_STORE={default_store}"
" ./manage.py cms --settings=bok_choy import {import_dir}".format(
default_store=self.default_store,
import_dir=self.imports_dir
)
)
# Ensure the test servers are available # Ensure the test servers are available
msg = colorize('green', "Starting test servers...") msg = colorize('green', "Starting test servers...")
print(msg) print(msg)
bokchoy_utils.start_servers() bokchoy_utils.start_servers(self.default_store)
msg = colorize('green', "Waiting for servers to start...") msg = colorize('green', "Waiting for servers to start...")
print(msg) print(msg)
...@@ -101,6 +111,7 @@ class BokChoyTestSuite(TestSuite): ...@@ -101,6 +111,7 @@ class BokChoyTestSuite(TestSuite):
# Construct the nosetests command, specifying where to save # Construct the nosetests command, specifying where to save
# screenshots and XUnit XML reports # screenshots and XUnit XML reports
cmd = [ cmd = [
"DEFAULT_STORE={}".format(self.default_store),
"SCREENSHOT_DIR='{}'".format(self.log_dir), "SCREENSHOT_DIR='{}'".format(self.log_dir),
"HAR_DIR='{}'".format(self.har_dir), "HAR_DIR='{}'".format(self.har_dir),
"SELENIUM_DRIVER_LOG_DIR='{}'".format(self.log_dir), "SELENIUM_DRIVER_LOG_DIR='{}'".format(self.log_dir),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment