tags to ensure that it is valid XML
+ grade_response_dict['msg'] = "
%s
" % grade_response_dict['msg']
+
+ # Save the response dictionary
+ self._grade_response = grade_response_dict
diff --git a/lms/djangoapps/courseware/mock_xqueue_server/test_mock_xqueue_server.py b/lms/djangoapps/courseware/mock_xqueue_server/test_mock_xqueue_server.py
new file mode 100644
index 0000000000..4e4d95f23b
--- /dev/null
+++ b/lms/djangoapps/courseware/mock_xqueue_server/test_mock_xqueue_server.py
@@ -0,0 +1,78 @@
+import mock
+import unittest
+import threading
+import json
+import urllib
+import urlparse
+import time
+from mock_xqueue_server import MockXQueueServer, MockXQueueRequestHandler
+
+
+class MockXQueueServerTest(unittest.TestCase):
+ '''
+ A mock version of the XQueue server that listens on a local
+ port and responds with pre-defined grade messages.
+
+ Used for lettuce BDD tests in lms/courseware/features/problems.feature
+ and lms/courseware/features/problems.py
+
+ This is temporary and will be removed when XQueue is
+ rewritten using celery.
+ '''
+
+ def setUp(self):
+
+ # Create the server
+ server_port = 8034
+ self.server_url = 'http://127.0.0.1:%d' % server_port
+ self.server = MockXQueueServer(server_port,
+ {'correct': True, 'score': 1, 'msg': ''})
+
+ # Start the server in a separate daemon thread
+ server_thread = threading.Thread(target=self.server.serve_forever)
+ server_thread.daemon = True
+ server_thread.start()
+
+ def tearDown(self):
+
+ # Stop the server, freeing up the port
+ self.server.shutdown()
+
+ def test_grade_request(self):
+
+ # Patch post_to_url() so we can intercept
+ # outgoing POST requests from the server
+ MockXQueueRequestHandler.post_to_url = mock.Mock()
+
+ # Send a grade request
+ callback_url = 'http://127.0.0.1:8000/test_callback'
+
+ grade_header = json.dumps({'lms_callback_url': callback_url,
+ 'lms_key': 'test_queuekey',
+ 'queue_name': 'test_queue'})
+
+ grade_body = json.dumps({'student_info': 'test',
+ 'grader_payload': 'test',
+ 'student_response': 'test'})
+
+ grade_request = {'xqueue_header': grade_header,
+ 'xqueue_body': grade_body}
+
+ response_handle = urllib.urlopen(self.server_url + '/xqueue/submit',
+ urllib.urlencode(grade_request))
+
+ response_dict = json.loads(response_handle.read())
+
+ # Expect that the response is success
+ self.assertEqual(response_dict['return_code'], 0)
+
+ # Wait a bit before checking that the server posted back
+ time.sleep(3)
+
+ # Expect that the server tries to post back the grading info
+ xqueue_body = json.dumps({'correct': True, 'score': 1,
+ 'msg': '
'})
+ expected_callback_dict = {'xqueue_header': grade_header,
+ 'xqueue_body': xqueue_body}
+ MockXQueueRequestHandler.post_to_url.assert_called_with(callback_url,
+ expected_callback_dict)
diff --git a/lms/djangoapps/courseware/model_data.py b/lms/djangoapps/courseware/model_data.py
index 35deda5d6b..b725f64308 100644
--- a/lms/djangoapps/courseware/model_data.py
+++ b/lms/djangoapps/courseware/model_data.py
@@ -1,3 +1,7 @@
+"""
+Classes to provide the LMS runtime data storage to XBlocks
+"""
+
import json
from collections import namedtuple, defaultdict
from itertools import chain
@@ -14,10 +18,16 @@ from xblock.core import Scope
class InvalidWriteError(Exception):
- pass
+ """
+ Raised to indicate that writing to a particular key
+ in the KeyValueStore is disabled
+ """
def chunks(items, chunk_size):
+ """
+ Yields the values from items in chunks of size chunk_size
+ """
items = list(items)
return (items[i:i + chunk_size] for i in xrange(0, len(items), chunk_size))
@@ -67,6 +77,15 @@ class ModelDataCache(object):
"""
def get_child_descriptors(descriptor, depth, descriptor_filter):
+ """
+ Return a list of all child descriptors down to the specified depth
+ that match the descriptor filter. Includes `descriptor`
+
+ descriptor: The parent to search inside
+ depth: The number of levels to descend, or None for infinite depth
+ descriptor_filter(descriptor): A function that returns True
+ if descriptor should be included in the results
+ """
if descriptor_filter(descriptor):
descriptors = [descriptor]
else:
@@ -121,7 +140,7 @@ class ModelDataCache(object):
'module_state_key__in',
(descriptor.location.url() for descriptor in self.descriptors),
course_id=self.course_id,
- student=self.user,
+ student=self.user.pk,
)
elif scope == Scope.content:
return self._chunked_query(
@@ -145,13 +164,13 @@ class ModelDataCache(object):
XModuleStudentPrefsField,
'module_type__in',
set(descriptor.location.category for descriptor in self.descriptors),
- student=self.user,
+ student=self.user.pk,
field_name__in=set(field.name for field in fields),
)
elif scope == Scope.student_info:
return self._query(
XModuleStudentInfoField,
- student=self.user,
+ student=self.user.pk,
field_name__in=set(field.name for field in fields),
)
else:
@@ -168,6 +187,9 @@ class ModelDataCache(object):
return scope_map
def _cache_key_from_kvs_key(self, key):
+ """
+ Return the key used in the ModelDataCache for the specified KeyValueStore key
+ """
if key.scope == Scope.student_state:
return (key.scope, key.block_scope_id.url())
elif key.scope == Scope.content:
@@ -180,6 +202,10 @@ class ModelDataCache(object):
return (key.scope, key.field_name)
def _cache_key_from_field_object(self, scope, field_object):
+ """
+ Return the key used in the ModelDataCache for the specified scope and
+ field
+ """
if scope == Scope.student_state:
return (scope, field_object.module_state_key)
elif scope == Scope.content:
@@ -230,7 +256,7 @@ class ModelDataCache(object):
usage_id='%s-%s' % (self.course_id, key.block_scope_id.url()),
)
elif key.scope == Scope.student_preferences:
- field_object, _= XModuleStudentPrefsField.objects.get_or_create(
+ field_object, _ = XModuleStudentPrefsField.objects.get_or_create(
field_name=key.field_name,
module_type=key.block_scope_id,
student=self.user,
@@ -276,6 +302,7 @@ class LmsKeyValueStore(KeyValueStore):
Scope.student_info,
Scope.children,
)
+
def __init__(self, descriptor_model_data, model_data_cache):
self._descriptor_model_data = descriptor_model_data
self._model_data_cache = model_data_cache
@@ -357,4 +384,3 @@ class LmsKeyValueStore(KeyValueStore):
LmsUsage = namedtuple('LmsUsage', 'id, def_id')
-
diff --git a/lms/envs/acceptance.py b/lms/envs/acceptance.py
index 3dac545367..6d96dfeb81 100644
--- a/lms/envs/acceptance.py
+++ b/lms/envs/acceptance.py
@@ -40,6 +40,18 @@ DATABASES = {
}
}
+# Set up XQueue information so that the lms will send
+# requests to a mock XQueue server running locally
+XQUEUE_PORT = 8027
+XQUEUE_INTERFACE = {
+ "url": "http://127.0.0.1:%d" % XQUEUE_PORT,
+ "django_auth": {
+ "username": "lms",
+ "password": "***REMOVED***"
+ },
+ "basic_auth": ('anant', 'agarwal'),
+}
+
# Do not display the YouTube videos in the browser while running the
# acceptance tests. This makes them faster and more reliable
MITX_FEATURES['STUB_VIDEO_FOR_TESTING'] = True
diff --git a/lms/static/images/BerkeleyX-on-edx-logo.png b/lms/static/images/BerkeleyX-on-edx-logo.png
index 6c5a828503..cb765ce2fa 100644
Binary files a/lms/static/images/BerkeleyX-on-edx-logo.png and b/lms/static/images/BerkeleyX-on-edx-logo.png differ
diff --git a/lms/static/images/university/berkeley/berkeley.png b/lms/static/images/university/berkeley/berkeley.png
index ca85266538..9fb7ffa6e7 100644
Binary files a/lms/static/images/university/berkeley/berkeley.png and b/lms/static/images/university/berkeley/berkeley.png differ
diff --git a/lms/static/images/university/berkeley/berkeley_bw.png b/lms/static/images/university/berkeley/berkeley_bw.png
index 9904e61315..77204c3913 100644
Binary files a/lms/static/images/university/berkeley/berkeley_bw.png and b/lms/static/images/university/berkeley/berkeley_bw.png differ
diff --git a/lms/templates/static_templates/jobs.html b/lms/templates/static_templates/jobs.html
index 2f6713fd06..e33ff62e9a 100644
--- a/lms/templates/static_templates/jobs.html
+++ b/lms/templates/static_templates/jobs.html
@@ -73,41 +73,6 @@
-->
-
-
-
ASSOCIATE LEGAL COUNSEL
-
-
We are seeking a talented lawyer with the ability to operate independently in a fast-paced environment and work proactively with all members of the edX team. You must have thorough knowledge of intellectual property law, contracts and licensing.
-
-
Key Responsibilities:
-
- - Drive the negotiating, reviewing, drafting and overseeing of a wide range of transactional arrangements, including collaborations related to the provision of online education, inbound and outbound licensing of intellectual property, strategic partnerships, nondisclosure agreements, and services agreements.
- - Provide counseling on the legal implications/considerations of business and technical strategies and projects, with special emphasis on regulations related to higher education, data security and privacy.
- - Provide advice and support company-wide on a variety of legal issues in a timely and effective manner.
- - Assist on other matters as needed.
-
-
-
Requirements:
-
-
- - JD from an accredited law school
- - Massachusetts bar admission required
- - 2-3 years of transactional experience at a major law firm and/or as an in-house counselor
- - Substantial IP licensing experience
- - Knowledge of copyright, trademark and patent law
- - Experience with open source content and open source software preferred
- - Outstanding communications skills (written and oral)
- - Experience with drafting and legal review of Internet privacy policies and terms of use.
- - Understanding of how to balance legal risks with business objectives
- - Ability to develop an innovative approach to legal issues in support of strategic business initiatives
- - An internal business and customer focused proactive attitude with ability to prioritize effectively
- - Experience with higher education preferred but not required
-
-
If you are interested in this position, please send an email to jobs@edx.org.
-
-
-
-
DIRECTOR OF EDUCATIONAL SERVICES
@@ -369,40 +334,6 @@
-
-
-
DIRECTOR ENGINEERING, OPEN SOURCE COMMUNITY MANAGER
-
In edX courses, students make (and break) electronic circuits, they manipulate molecules on the fly and they do it all at once, in their tens of thousands. We have great Professors and great Universities. But we can’t possibly keep up with all the great ideas out there, so we’re making our platform open source, to turn up the volume on great education. To do that well, we’ll need a Director of Engineering who can lead our Open Source Community efforts.
-
Responsibilities:
-
- - Define and implement software design standards that make the open source community most welcome and productive.
- - Work with others to establish the governance standards for the edX Open Source Platform, establish the infrastructure, and manage the team to deliver releases and leverage our University partners and stakeholders to
make the edX platform the world’s best learning platform.
- - Help the organization recognize the benefits and limitations inherent in open source solutions.
- - Establish best practices and key tool usage, especially those based on industry standards.
- - Provide visibility for the leadership team into the concerns and challenges faced by the open source community.
- - Foster a thriving community by providing the communication, documentation and feedback that they need to be enthusiastic.
- - Maximize the good code design coming from the open source community.
- - Provide the wit and firmness that the community needs to channel their energy productively.
- - Tactfully balance the internal needs of the organization to pursue new opportunities with the community’s need to participate in the platform’s evolution.
- - Shorten lines of communication and build trust across entire team
-
-
Qualifications:
-
-
- - Bachelors, preferably Masters in Computer Science
- - Solid communication skills, especially written
- - Committed to Agile practice, Scrum and Kanban
- - Charm and humor
- - Deep familiarity with Open Source, participant and contributor
- - Python, Django, Javascript
- - Commitment to support your technical recommendations, both within and beyond the organization.
-
-
-
If you are interested in this position, please send an email to jobs@edx.org.
-
-
-
-
SOFTWARE ENGINEER
@@ -441,7 +372,6 @@