From e980f8b296565e0eb46ac9d883a135f1b45817c8 Mon Sep 17 00:00:00 2001 From: Victor Shnayder Date: Sun, 12 Aug 2012 16:59:07 -0400 Subject: [PATCH 1/2] add notes on how to run individual tests --- doc/development.md | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/doc/development.md b/doc/development.md index 9d6628732a..44965cb0de 100644 --- a/doc/development.md +++ b/doc/development.md @@ -34,12 +34,34 @@ This will import all courses in your data directory into mongodb This runs all the tests (long, uses collectstatic): rake test - + +If if you aren't changing static files, can run `rake test` once, then run + + rake fasttest_{lms,cms} + xmodule can be tested independently, with this: rake test_common/lib/xmodule - + To see all available rake commands, do this: rake -T - \ No newline at end of file + +To run a single django test class: + + django-admin.py test --settings=lms.envs.test --pythonpath=. lms/djangoapps/courseware/tests/tests.py:TestViewAuth + +To run a single django test: + + django-admin.py test --settings=lms.envs.test --pythonpath=. lms/djangoapps/courseware/tests/tests.py:TestViewAuth.test_dark_launch + + +To run a single nose test file: + + nosetests common/lib/xmodule/xmodule/tests/test_stringify.py + +To run a single nose test: + + nosetests common/lib/xmodule/xmodule/tests/test_stringify.py:test_stringify + + From af7e70a9791c11c131ffde31a64c056e0a60f057 Mon Sep 17 00:00:00 2001 From: Victor Shnayder Date: Sun, 12 Aug 2012 17:21:40 -0400 Subject: [PATCH 2/2] Log content problems as warnings, not errors * will avoid newrelic complaining * NOTE: Is this what we want post-ship? - need some way of notifying instructors of problems --- common/djangoapps/student/views.py | 4 ++-- common/lib/capa/capa/capa_problem.py | 16 ++++++++-------- common/lib/capa/capa/inputtypes.py | 14 +++++++------- common/lib/xmodule/xmodule/capa_module.py | 2 +- common/lib/xmodule/xmodule/modulestore/xml.py | 9 +++++---- common/lib/xmodule/xmodule/x_module.py | 9 +++++---- 6 files changed, 28 insertions(+), 26 deletions(-) diff --git a/common/djangoapps/student/views.py b/common/djangoapps/student/views.py index 8093a5a51a..ab22cc0d82 100644 --- a/common/djangoapps/student/views.py +++ b/common/djangoapps/student/views.py @@ -128,7 +128,7 @@ def dashboard(request): try: courses.append(course_from_id(enrollment.course_id)) except ItemNotFoundError: - log.error("User {0} enrolled in non-existant course {1}" + log.error("User {0} enrolled in non-existent course {1}" .format(user.username, enrollment.course_id)) message = "" @@ -182,7 +182,7 @@ def change_enrollment(request): try: course = course_from_id(course_id) except ItemNotFoundError: - log.error("User {0} tried to enroll in non-existant course {1}" + log.warning("User {0} tried to enroll in non-existant course {1}" .format(user.username, enrollment.course_id)) return {'success': False, 'error': 'The course requested does not exist.'} diff --git a/common/lib/capa/capa/capa_problem.py b/common/lib/capa/capa/capa_problem.py index 92823667e7..d1798f2c67 100644 --- a/common/lib/capa/capa/capa_problem.py +++ b/common/lib/capa/capa/capa_problem.py @@ -229,14 +229,14 @@ class LoncapaProblem(object): Calls the Response for each question in this problem, to do the actual grading. ''' - + self.student_answers = convert_files_to_filenames(answers) - + oldcmap = self.correct_map # old CorrectMap newcmap = CorrectMap() # start new with empty CorrectMap # log.debug('Responders: %s' % self.responders) for responder in self.responders.values(): # Call each responsetype instance to do actual grading - if 'filesubmission' in responder.allowed_inputfields: # File objects are passed only if responsetype + if 'filesubmission' in responder.allowed_inputfields: # File objects are passed only if responsetype # explicitly allows for file submissions results = responder.evaluate_answers(answers, oldcmap) else: @@ -295,9 +295,9 @@ class LoncapaProblem(object): try: ifp = self.system.filestore.open(file) # open using ModuleSystem OSFS filestore except Exception as err: - log.error('Error %s in problem xml include: %s' % ( + log.warning('Error %s in problem xml include: %s' % ( err, etree.tostring(inc, pretty_print=True))) - log.error('Cannot find file %s in %s' % ( + log.warning('Cannot find file %s in %s' % ( file, self.system.filestore)) # if debugging, don't fail - just log error # TODO (vshnayder): need real error handling, display to users @@ -306,11 +306,11 @@ class LoncapaProblem(object): else: continue try: - incxml = etree.XML(ifp.read()) # read in and convert to XML + incxml = etree.XML(ifp.read()) # read in and convert to XML except Exception as err: - log.error('Error %s in problem xml include: %s' % ( + log.warning('Error %s in problem xml include: %s' % ( err, etree.tostring(inc, pretty_print=True))) - log.error('Cannot parse XML in %s' % (file)) + log.warning('Cannot parse XML in %s' % (file)) # if debugging, don't fail - just log error # TODO (vshnayder): same as above if not self.system.get('DEBUG'): diff --git a/common/lib/capa/capa/inputtypes.py b/common/lib/capa/capa/inputtypes.py index 0c47892598..c3acbdda91 100644 --- a/common/lib/capa/capa/inputtypes.py +++ b/common/lib/capa/capa/inputtypes.py @@ -313,13 +313,13 @@ def filesubmission(element, value, status, render_template, msg=''): if status == 'incomplete': # Flag indicating that the problem has been queued, 'msg' is length of queue status = 'queued' queue_len = msg - msg = 'Submitted to grader. (Queue length: %s)' % queue_len + msg = 'Submitted to grader. (Queue length: %s)' % queue_len - context = { 'id': eid, 'state': status, 'msg': msg, 'value': value, + context = { 'id': eid, 'state': status, 'msg': msg, 'value': value, 'queue_len': queue_len } html = render_template("filesubmission.html", context) - return etree.XML(html) + return etree.XML(html) #----------------------------------------------------------------------------- @@ -339,16 +339,16 @@ def textbox(element, value, status, render_template, msg=''): hidden = element.get('hidden', '') # if specified, then textline is hidden and id is stored in div of name given by hidden if not value: value = element.text # if no student input yet, then use the default input given by the problem - + # Check if problem has been queued queue_len = 0 if status == 'incomplete': # Flag indicating that the problem has been queued, 'msg' is length of queue - status = 'queued' + status = 'queued' queue_len = msg - msg = 'Submitted to grader. (Queue length: %s)' % queue_len + msg = 'Submitted to grader. (Queue length: %s)' % queue_len # For CodeMirror - mode = element.get('mode','python') + mode = element.get('mode','python') linenumbers = element.get('linenumbers','true') tabsize = element.get('tabsize','4') tabsize = int(tabsize) diff --git a/common/lib/xmodule/xmodule/capa_module.py b/common/lib/xmodule/xmodule/capa_module.py index eb083e97db..f12b1c2be4 100644 --- a/common/lib/xmodule/xmodule/capa_module.py +++ b/common/lib/xmodule/xmodule/capa_module.py @@ -150,7 +150,7 @@ class CapaModule(XModule): # TODO (vshnayder): do modules need error handlers too? # We shouldn't be switching on DEBUG. if self.system.DEBUG: - log.error(msg) + log.warning(msg) # TODO (vshnayder): This logic should be general, not here--and may # want to preserve the data instead of replacing it. # e.g. in the CMS diff --git a/common/lib/xmodule/xmodule/modulestore/xml.py b/common/lib/xmodule/xmodule/modulestore/xml.py index 2dc3b33323..8c4c373d4f 100644 --- a/common/lib/xmodule/xmodule/modulestore/xml.py +++ b/common/lib/xmodule/xmodule/modulestore/xml.py @@ -50,8 +50,9 @@ class ImportSystem(XMLParsingSystem, MakoDescriptorSystem): # have been imported into the cms from xml xml = clean_out_mako_templating(xml) xml_data = etree.fromstring(xml) - except: - log.exception("Unable to parse xml: {xml}".format(xml=xml)) + except Exception as err: + log.warning("Unable to parse xml: {err}, xml: {xml}".format( + err=str(err), xml=xml)) raise # VS[compat]. Take this out once course conversion is done @@ -194,7 +195,7 @@ class XMLModuleStore(ModuleStoreBase): if org is None: msg = ("No 'org' attribute set for course in {dir}. " "Using default 'edx'".format(dir=course_dir)) - log.error(msg) + log.warning(msg) tracker(msg) org = 'edx' @@ -206,7 +207,7 @@ class XMLModuleStore(ModuleStoreBase): dir=course_dir, default=course_dir )) - log.error(msg) + log.warning(msg) tracker(msg) course = course_dir diff --git a/common/lib/xmodule/xmodule/x_module.py b/common/lib/xmodule/xmodule/x_module.py index 2cd51b9e6e..3b89f29989 100644 --- a/common/lib/xmodule/xmodule/x_module.py +++ b/common/lib/xmodule/xmodule/x_module.py @@ -522,7 +522,7 @@ class XModuleDescriptor(Plugin, HTMLSnippet): # Put import here to avoid circular import errors from xmodule.error_module import ErrorDescriptor msg = "Error loading from xml." - log.exception(msg) + log.warning(msg + " " + str(err)) system.error_tracker(msg) err_msg = msg + "\n" + exc_info_to_str(sys.exc_info()) descriptor = ErrorDescriptor.from_xml(xml_data, system, org, course, @@ -615,9 +615,10 @@ class DescriptorSystem(object): try: x = access_some_resource() check_some_format(x) - except SomeProblem: - msg = 'Grommet {0} is broken'.format(x) - log.exception(msg) # don't rely on handler to log + except SomeProblem as err: + msg = 'Grommet {0} is broken: {1}'.format(x, str(err)) + log.warning(msg) # don't rely on tracker to log + # NOTE: we generally don't want content errors logged as errors self.system.error_tracker(msg) # work around return 'Oops, couldn't load grommet'