Added configuration for running tests using the bok-choy framework
This commit is contained in:
1
Gemfile
1
Gemfile
@@ -6,6 +6,7 @@ gem 'neat', '~> 1.4.0'
|
||||
gem 'colorize', '~> 0.5.8'
|
||||
gem 'launchy', '~> 2.1.2'
|
||||
gem 'sys-proctable', '~> 0.9.3'
|
||||
gem 'dalli', '~> 2.6.4'
|
||||
# These gems aren't actually required; they are used by Linux and Mac to
|
||||
# detect when files change. If these gems are not installed, the system
|
||||
# will fall back to polling files.
|
||||
|
||||
@@ -6,6 +6,7 @@ GEM
|
||||
sass (>= 3.2.0)
|
||||
thor
|
||||
colorize (0.5.8)
|
||||
dalli (2.6.4)
|
||||
ffi (1.9.0)
|
||||
launchy (2.1.2)
|
||||
addressable (~> 2.3)
|
||||
@@ -26,6 +27,7 @@ PLATFORMS
|
||||
DEPENDENCIES
|
||||
bourbon (~> 3.1.8)
|
||||
colorize (~> 0.5.8)
|
||||
dalli (~> 2.6.4)
|
||||
launchy (~> 2.1.2)
|
||||
neat (~> 1.4.0)
|
||||
rake (~> 10.0.3)
|
||||
|
||||
125
cms/envs/bok_choy.auth.json
Normal file
125
cms/envs/bok_choy.auth.json
Normal file
@@ -0,0 +1,125 @@
|
||||
{
|
||||
"ANALYTICS_API_KEY": "",
|
||||
"AWS_ACCESS_KEY_ID": "",
|
||||
"AWS_SECRET_ACCESS_KEY": "",
|
||||
"CELERY_BROKER_PASSWORD": "celery",
|
||||
"CELERY_BROKER_USER": "celery",
|
||||
"CONTENTSTORE": {
|
||||
"DOC_STORE_CONFIG": {
|
||||
"collection": "modulestore",
|
||||
"db": "test",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"password": "password",
|
||||
"port": 27017,
|
||||
"user": "edxapp"
|
||||
},
|
||||
"ENGINE": "xmodule.contentstore.mongo.MongoContentStore",
|
||||
"OPTIONS": {
|
||||
"db": "test",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"password": "password",
|
||||
"port": 27017,
|
||||
"user": "edxapp"
|
||||
}
|
||||
},
|
||||
"DATABASES": {
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.mysql",
|
||||
"HOST": "localhost",
|
||||
"NAME": "test",
|
||||
"PASSWORD": "",
|
||||
"PORT": "3306",
|
||||
"USER": "root"
|
||||
}
|
||||
},
|
||||
"DOC_STORE_CONFIG": {
|
||||
"collection": "modulestore",
|
||||
"db": "test",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"password": "password",
|
||||
"port": 27017,
|
||||
"user": "edxapp"
|
||||
},
|
||||
"MODULESTORE": {
|
||||
"default": {
|
||||
"DOC_STORE_CONFIG": {
|
||||
"collection": "modulestore",
|
||||
"db": "test",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"password": "password",
|
||||
"port": 27017,
|
||||
"user": "edxapp"
|
||||
},
|
||||
"ENGINE": "xmodule.modulestore.mongo.DraftMongoModuleStore",
|
||||
"OPTIONS": {
|
||||
"collection": "modulestore",
|
||||
"db": "test",
|
||||
"default_class": "xmodule.hidden_module.HiddenDescriptor",
|
||||
"fs_root": "** OVERRIDDEN **",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"password": "password",
|
||||
"port": 27017,
|
||||
"render_template": "edxmako.shortcuts.render_to_string",
|
||||
"user": "edxapp"
|
||||
}
|
||||
},
|
||||
"direct": {
|
||||
"DOC_STORE_CONFIG": {
|
||||
"collection": "modulestore",
|
||||
"db": "test",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"password": "password",
|
||||
"port": 27017,
|
||||
"user": "edxapp"
|
||||
},
|
||||
"ENGINE": "xmodule.modulestore.mongo.MongoModuleStore",
|
||||
"OPTIONS": {
|
||||
"collection": "modulestore",
|
||||
"db": "test",
|
||||
"default_class": "xmodule.hidden_module.HiddenDescriptor",
|
||||
"fs_root": "** OVERRIDDEN **",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"password": "password",
|
||||
"port": 27017,
|
||||
"render_template": "edxmako.shortcuts.render_to_string",
|
||||
"user": "edxapp"
|
||||
}
|
||||
}
|
||||
},
|
||||
"OPEN_ENDED_GRADING_INTERFACE": {
|
||||
"grading_controller": "grading_controller",
|
||||
"password": "password",
|
||||
"peer_grading": "peer_grading",
|
||||
"staff_grading": "staff_grading",
|
||||
"url": "http://localhost:18060/",
|
||||
"username": "lms"
|
||||
},
|
||||
"SECRET_KEY": "",
|
||||
"XQUEUE_INTERFACE": {
|
||||
"basic_auth": [
|
||||
"edx",
|
||||
"edx"
|
||||
],
|
||||
"django_auth": {
|
||||
"password": "password",
|
||||
"username": "lms"
|
||||
},
|
||||
"url": "http://localhost:18040"
|
||||
},
|
||||
"ZENDESK_API_KEY": "",
|
||||
"ZENDESK_USER": ""
|
||||
}
|
||||
99
cms/envs/bok_choy.env.json
Normal file
99
cms/envs/bok_choy.env.json
Normal file
@@ -0,0 +1,99 @@
|
||||
{
|
||||
"ANALYTICS_SERVER_URL": "",
|
||||
"BOOK_URL": "",
|
||||
"BUGS_EMAIL": "bugs@example.com",
|
||||
"BULK_EMAIL_DEFAULT_FROM_EMAIL": "no-reply@example.com",
|
||||
"CACHES": {
|
||||
"celery": {
|
||||
"BACKEND": "django.core.cache.backends.memcached.MemcachedCache",
|
||||
"KEY_FUNCTION": "util.memcache.safe_key",
|
||||
"KEY_PREFIX": "integration_celery",
|
||||
"LOCATION": [
|
||||
"localhost:11211"
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"BACKEND": "django.core.cache.backends.memcached.MemcachedCache",
|
||||
"KEY_FUNCTION": "util.memcache.safe_key",
|
||||
"KEY_PREFIX": "sandbox_default",
|
||||
"LOCATION": [
|
||||
"localhost:11211"
|
||||
]
|
||||
},
|
||||
"general": {
|
||||
"BACKEND": "django.core.cache.backends.memcached.MemcachedCache",
|
||||
"KEY_FUNCTION": "util.memcache.safe_key",
|
||||
"KEY_PREFIX": "sandbox_general",
|
||||
"LOCATION": [
|
||||
"localhost:11211"
|
||||
]
|
||||
},
|
||||
"mongo_metadata_inheritance": {
|
||||
"BACKEND": "django.core.cache.backends.memcached.MemcachedCache",
|
||||
"KEY_FUNCTION": "util.memcache.safe_key",
|
||||
"KEY_PREFIX": "integration_mongo_metadata_inheritance",
|
||||
"LOCATION": [
|
||||
"localhost:11211"
|
||||
]
|
||||
},
|
||||
"staticfiles": {
|
||||
"BACKEND": "django.core.cache.backends.memcached.MemcachedCache",
|
||||
"KEY_FUNCTION": "util.memcache.safe_key",
|
||||
"KEY_PREFIX": "integration_static_files",
|
||||
"LOCATION": [
|
||||
"localhost:11211"
|
||||
]
|
||||
}
|
||||
},
|
||||
"CELERY_BROKER_HOSTNAME": "localhost",
|
||||
"CELERY_BROKER_TRANSPORT": "amqp",
|
||||
"CERT_QUEUE": "certificates",
|
||||
"CMS_BASE": "",
|
||||
"CODE_JAIL": {
|
||||
"limits": {
|
||||
"REALTIME": 3,
|
||||
"VMEM": 0
|
||||
}
|
||||
},
|
||||
"COMMENTS_SERVICE_KEY": "password",
|
||||
"COMMENTS_SERVICE_URL": "http://localhost:4567",
|
||||
"CONTACT_EMAIL": "info@example.com",
|
||||
"DEFAULT_FEEDBACK_EMAIL": "feedback@example.com",
|
||||
"DEFAULT_FROM_EMAIL": "registration@example.com",
|
||||
"EMAIL_BACKEND": "django.core.mail.backends.smtp.EmailBackend",
|
||||
"FEATURES": {
|
||||
"AUTH_USE_OPENID_PROVIDER": true,
|
||||
"CERTIFICATES_ENABLED": true,
|
||||
"ENABLE_DISCUSSION_SERVICE": true,
|
||||
"ENABLE_INSTRUCTOR_ANALYTICS": true,
|
||||
"ENABLE_S3_GRADE_DOWNLOADS": true,
|
||||
"PREVIEW_LMS_BASE": "",
|
||||
"SUBDOMAIN_BRANDING": false,
|
||||
"SUBDOMAIN_COURSE_LISTINGS": false
|
||||
},
|
||||
"FEEDBACK_SUBMISSION_EMAIL": "",
|
||||
"GITHUB_REPO_ROOT": "** OVERRIDDEN **",
|
||||
"GRADES_DOWNLOAD": {
|
||||
"BUCKET": "edx-grades",
|
||||
"ROOT_PATH": "/tmp/edx-s3/grades",
|
||||
"STORAGE_TYPE": "localfs"
|
||||
},
|
||||
"LMS_BASE": "",
|
||||
"LOCAL_LOGLEVEL": "INFO",
|
||||
"LOGGING_ENV": "sandbox",
|
||||
"LOG_DIR": "** OVERRIDDEN **",
|
||||
"MEDIA_URL": "",
|
||||
"MKTG_URL_LINK_MAP": {},
|
||||
"PLATFORM_NAME": "edX",
|
||||
"SEGMENT_IO_LMS": true,
|
||||
"SERVER_EMAIL": "devops@example.com",
|
||||
"SESSION_COOKIE_DOMAIN": null,
|
||||
"SITE_NAME": "localhost",
|
||||
"STATIC_ROOT_BASE": "** OVERRIDDEN **",
|
||||
"STATIC_URL_BASE": "/static/",
|
||||
"SYSLOG_SERVER": "",
|
||||
"TECH_SUPPORT_EMAIL": "technical@example.com",
|
||||
"THEME_NAME": "",
|
||||
"TIME_ZONE": "America/New_York",
|
||||
"WIKI_ENABLED": true
|
||||
}
|
||||
46
cms/envs/bok_choy.py
Normal file
46
cms/envs/bok_choy.py
Normal file
@@ -0,0 +1,46 @@
|
||||
# Settings for bok choy tests
|
||||
|
||||
import os
|
||||
from path import path
|
||||
|
||||
|
||||
########################## Prod-like settings ###################################
|
||||
# These should be as close as possible to the settings we use in production.
|
||||
# As in prod, we read in environment and auth variables from JSON files.
|
||||
# Unlike in prod, we use the JSON files stored in this repo.
|
||||
# This is a convenience for ensuring (a) that we can consistently find the files
|
||||
# and (b) that the files are the same in Jenkins as in local dev.
|
||||
os.environ['SERVICE_VARIANT'] = 'bok_choy'
|
||||
os.environ['CONFIG_ROOT'] = path(__file__).abspath().dirname()
|
||||
|
||||
from aws import * # pylint: disable=W0401, W0614
|
||||
|
||||
|
||||
######################### Testing overrides ####################################
|
||||
|
||||
# Needed for the `reset_db` management command
|
||||
INSTALLED_APPS += ('django_extensions',)
|
||||
|
||||
# Redirect to the test_root folder within the repo
|
||||
TEST_ROOT = CONFIG_ROOT.dirname().dirname() / "test_root"
|
||||
GITHUB_REPO_ROOT = (TEST_ROOT / "data").abspath()
|
||||
LOG_DIR = (TEST_ROOT / "log").abspath()
|
||||
|
||||
# Configure Mongo modulestore to use the test folder within the repo
|
||||
for store in ["default", "direct"]:
|
||||
MODULESTORE[store]['OPTIONS']['fs_root'] = (TEST_ROOT / "data").abspath()
|
||||
|
||||
# Enable django-pipeline and staticfiles
|
||||
STATIC_ROOT = (TEST_ROOT / "staticfiles").abspath()
|
||||
PIPELINE = True
|
||||
|
||||
# Silence noisy logs
|
||||
import logging
|
||||
LOG_OVERRIDES = [
|
||||
('track.middleware', logging.CRITICAL)
|
||||
]
|
||||
for log_name, log_level in LOG_OVERRIDES:
|
||||
logging.getLogger(log_name).setLevel(log_level)
|
||||
|
||||
# Unfortunately, we need to use debug mode to serve staticfiles
|
||||
DEBUG = True
|
||||
@@ -1,4 +1,4 @@
|
||||
import os
|
||||
|
||||
# Get the URL of the instance under test
|
||||
BASE_URL = os.environ.get('test_url', '')
|
||||
BASE_URL = os.environ.get('test_url', 'http://localhost:8003')
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import os
|
||||
|
||||
# Get the URL of the instance under test
|
||||
BASE_URL = os.environ.get('test_url', '')
|
||||
BASE_URL = os.environ.get('test_url', 'http://localhost:8031')
|
||||
|
||||
0
common/test/bok_choy/tests/__init__.py
Normal file
0
common/test/bok_choy/tests/__init__.py
Normal file
20
common/test/bok_choy/tests/test_info_pages.py
Normal file
20
common/test/bok_choy/tests/test_info_pages.py
Normal file
@@ -0,0 +1,20 @@
|
||||
"""
|
||||
Very simple test case to verify bok-choy integration.
|
||||
"""
|
||||
|
||||
from bok_choy.web_app_test import WebAppTest
|
||||
from edxapp_pages.lms.info import InfoPage
|
||||
|
||||
|
||||
class InfoPageTest(WebAppTest):
|
||||
"""
|
||||
Test that the top-level pages in the LMS load.
|
||||
"""
|
||||
|
||||
@property
|
||||
def page_object_classes(self):
|
||||
return [InfoPage]
|
||||
|
||||
def test_info(self):
|
||||
for section_name in InfoPage.sections():
|
||||
self.ui.visit('lms.info', section=section_name)
|
||||
@@ -20,6 +20,7 @@ set -e
|
||||
# because we couldn't think of a better place to put it)
|
||||
# - "lms-acceptance": Run the acceptance (Selenium) tests for the LMS
|
||||
# - "cms-acceptance": Run the acceptance (Selenium) tests for Studio
|
||||
# - "bok-choy": Run acceptance tests that use the bok-choy framework
|
||||
#
|
||||
# `SHARD` is a number (1, 2, or 3) indicating which subset of the tests
|
||||
# to build. Currently, "lms-acceptance" has two shards (1 and 2),
|
||||
@@ -95,4 +96,8 @@ END
|
||||
rake test:acceptance:cms["-v 3 --tag shard_${SHARD}"]
|
||||
;;
|
||||
|
||||
"bok-choy")
|
||||
rake test:bok_choy
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
114
lms/envs/bok_choy.auth.json
Normal file
114
lms/envs/bok_choy.auth.json
Normal file
@@ -0,0 +1,114 @@
|
||||
{
|
||||
"ANALYTICS_API_KEY": "",
|
||||
"AWS_ACCESS_KEY_ID": "",
|
||||
"AWS_SECRET_ACCESS_KEY": "",
|
||||
"CELERY_BROKER_PASSWORD": "celery",
|
||||
"CELERY_BROKER_USER": "celery",
|
||||
"CONTENTSTORE": {
|
||||
"DOC_STORE_CONFIG": {
|
||||
"collection": "modulestore",
|
||||
"db": "edxapp",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"password": "password",
|
||||
"port": 27017,
|
||||
"user": "edxapp"
|
||||
},
|
||||
"ENGINE": "xmodule.contentstore.mongo.MongoContentStore",
|
||||
"OPTIONS": {
|
||||
"db": "edxapp",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"password": "password",
|
||||
"port": 27017,
|
||||
"user": "edxapp"
|
||||
}
|
||||
},
|
||||
"DATABASES": {
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.mysql",
|
||||
"HOST": "localhost",
|
||||
"NAME": "test",
|
||||
"PASSWORD": "",
|
||||
"PORT": "3306",
|
||||
"USER": "root"
|
||||
}
|
||||
},
|
||||
"DOC_STORE_CONFIG": {
|
||||
"collection": "modulestore",
|
||||
"db": "test",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"password": "password",
|
||||
"port": 27017,
|
||||
"user": "edxapp"
|
||||
},
|
||||
"MODULESTORE": {
|
||||
"default": {
|
||||
"ENGINE": "xmodule.modulestore.mixed.MixedModuleStore",
|
||||
"OPTIONS": {
|
||||
"mappings": {},
|
||||
"stores": {
|
||||
"default": {
|
||||
"DOC_STORE_CONFIG": {
|
||||
"collection": "modulestore",
|
||||
"db": "test",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"password": "password",
|
||||
"port": 27017,
|
||||
"user": "edxapp"
|
||||
},
|
||||
"ENGINE": "xmodule.modulestore.mongo.MongoModuleStore",
|
||||
"OPTIONS": {
|
||||
"collection": "modulestore",
|
||||
"db": "test",
|
||||
"default_class": "xmodule.hidden_module.HiddenDescriptor",
|
||||
"fs_root": "** OVERRIDDEN **",
|
||||
"host": [
|
||||
"localhost"
|
||||
],
|
||||
"password": "password",
|
||||
"port": 27017,
|
||||
"render_template": "edxmako.shortcuts.render_to_string",
|
||||
"user": "edxapp"
|
||||
}
|
||||
},
|
||||
"xml": {
|
||||
"ENGINE": "xmodule.modulestore.xml.XMLModuleStore",
|
||||
"OPTIONS": {
|
||||
"data_dir": "** OVERRIDDEN **",
|
||||
"default_class": "xmodule.hidden_module.HiddenDescriptor"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"OPEN_ENDED_GRADING_INTERFACE": {
|
||||
"grading_controller": "grading_controller",
|
||||
"password": "password",
|
||||
"peer_grading": "peer_grading",
|
||||
"staff_grading": "staff_grading",
|
||||
"url": "http://localhost:18060/",
|
||||
"username": "lms"
|
||||
},
|
||||
"SECRET_KEY": "",
|
||||
"XQUEUE_INTERFACE": {
|
||||
"basic_auth": [
|
||||
"edx",
|
||||
"edx"
|
||||
],
|
||||
"django_auth": {
|
||||
"password": "password",
|
||||
"username": "lms"
|
||||
},
|
||||
"url": "http://localhost:18040"
|
||||
},
|
||||
"ZENDESK_API_KEY": "",
|
||||
"ZENDESK_USER": ""
|
||||
}
|
||||
99
lms/envs/bok_choy.env.json
Normal file
99
lms/envs/bok_choy.env.json
Normal file
@@ -0,0 +1,99 @@
|
||||
{
|
||||
"ANALYTICS_SERVER_URL": "",
|
||||
"BOOK_URL": "",
|
||||
"BUGS_EMAIL": "bugs@example.com",
|
||||
"BULK_EMAIL_DEFAULT_FROM_EMAIL": "no-reply@example.com",
|
||||
"CACHES": {
|
||||
"celery": {
|
||||
"BACKEND": "django.core.cache.backends.memcached.MemcachedCache",
|
||||
"KEY_FUNCTION": "util.memcache.safe_key",
|
||||
"KEY_PREFIX": "integration_celery",
|
||||
"LOCATION": [
|
||||
"localhost:11211"
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"BACKEND": "django.core.cache.backends.memcached.MemcachedCache",
|
||||
"KEY_FUNCTION": "util.memcache.safe_key",
|
||||
"KEY_PREFIX": "sandbox_default",
|
||||
"LOCATION": [
|
||||
"localhost:11211"
|
||||
]
|
||||
},
|
||||
"general": {
|
||||
"BACKEND": "django.core.cache.backends.memcached.MemcachedCache",
|
||||
"KEY_FUNCTION": "util.memcache.safe_key",
|
||||
"KEY_PREFIX": "sandbox_general",
|
||||
"LOCATION": [
|
||||
"localhost:11211"
|
||||
]
|
||||
},
|
||||
"mongo_metadata_inheritance": {
|
||||
"BACKEND": "django.core.cache.backends.memcached.MemcachedCache",
|
||||
"KEY_FUNCTION": "util.memcache.safe_key",
|
||||
"KEY_PREFIX": "integration_mongo_metadata_inheritance",
|
||||
"LOCATION": [
|
||||
"localhost:11211"
|
||||
]
|
||||
},
|
||||
"staticfiles": {
|
||||
"BACKEND": "django.core.cache.backends.memcached.MemcachedCache",
|
||||
"KEY_FUNCTION": "util.memcache.safe_key",
|
||||
"KEY_PREFIX": "integration_static_files",
|
||||
"LOCATION": [
|
||||
"localhost:11211"
|
||||
]
|
||||
}
|
||||
},
|
||||
"CELERY_BROKER_HOSTNAME": "localhost",
|
||||
"CELERY_BROKER_TRANSPORT": "amqp",
|
||||
"CERT_QUEUE": "certificates",
|
||||
"CMS_BASE": "",
|
||||
"CODE_JAIL": {
|
||||
"limits": {
|
||||
"REALTIME": 3,
|
||||
"VMEM": 0
|
||||
}
|
||||
},
|
||||
"COMMENTS_SERVICE_KEY": "password",
|
||||
"COMMENTS_SERVICE_URL": "http://localhost:4567",
|
||||
"CONTACT_EMAIL": "info@example.com",
|
||||
"DEFAULT_FEEDBACK_EMAIL": "feedback@example.com",
|
||||
"DEFAULT_FROM_EMAIL": "registration@example.com",
|
||||
"EMAIL_BACKEND": "django.core.mail.backends.smtp.EmailBackend",
|
||||
"FEATURES": {
|
||||
"AUTH_USE_OPENID_PROVIDER": true,
|
||||
"CERTIFICATES_ENABLED": true,
|
||||
"ENABLE_DISCUSSION_SERVICE": true,
|
||||
"ENABLE_INSTRUCTOR_ANALYTICS": true,
|
||||
"ENABLE_S3_GRADE_DOWNLOADS": true,
|
||||
"PREVIEW_LMS_BASE": "",
|
||||
"SUBDOMAIN_BRANDING": false,
|
||||
"SUBDOMAIN_COURSE_LISTINGS": false
|
||||
},
|
||||
"FEEDBACK_SUBMISSION_EMAIL": "",
|
||||
"GITHUB_REPO_ROOT": "** OVERRIDDEN **",
|
||||
"GRADES_DOWNLOAD": {
|
||||
"BUCKET": "edx-grades",
|
||||
"ROOT_PATH": "/tmp/edx-s3/grades",
|
||||
"STORAGE_TYPE": "localfs"
|
||||
},
|
||||
"LMS_BASE": "",
|
||||
"LOCAL_LOGLEVEL": "INFO",
|
||||
"LOGGING_ENV": "sandbox",
|
||||
"LOG_DIR": "** OVERRIDDEN **",
|
||||
"MEDIA_URL": "",
|
||||
"MKTG_URL_LINK_MAP": {},
|
||||
"PLATFORM_NAME": "edX",
|
||||
"SEGMENT_IO_LMS": true,
|
||||
"SERVER_EMAIL": "devops@example.com",
|
||||
"SESSION_COOKIE_DOMAIN": null,
|
||||
"SITE_NAME": "localhost",
|
||||
"STATIC_ROOT_BASE": "** OVERRIDDEN **",
|
||||
"STATIC_URL_BASE": "/static/",
|
||||
"SYSLOG_SERVER": "",
|
||||
"TECH_SUPPORT_EMAIL": "technical@example.com",
|
||||
"THEME_NAME": "",
|
||||
"TIME_ZONE": "America/New_York",
|
||||
"WIKI_ENABLED": true
|
||||
}
|
||||
54
lms/envs/bok_choy.py
Normal file
54
lms/envs/bok_choy.py
Normal file
@@ -0,0 +1,54 @@
|
||||
# Settings for bok choy tests
|
||||
|
||||
import os
|
||||
from path import path
|
||||
|
||||
|
||||
CONFIG_ROOT = path(__file__).abspath().dirname()
|
||||
TEST_ROOT = CONFIG_ROOT.dirname().dirname() / "test_root"
|
||||
|
||||
########################## Prod-like settings ###################################
|
||||
# These should be as close as possible to the settings we use in production.
|
||||
# As in prod, we read in environment and auth variables from JSON files.
|
||||
# Unlike in prod, we use the JSON files stored in this repo.
|
||||
# This is a convenience for ensuring (a) that we can consistently find the files
|
||||
# and (b) that the files are the same in Jenkins as in local dev.
|
||||
os.environ['SERVICE_VARIANT'] = 'bok_choy'
|
||||
os.environ['CONFIG_ROOT'] = CONFIG_ROOT
|
||||
|
||||
from aws import * # pylint: disable=W0401, W0614
|
||||
|
||||
|
||||
######################### Testing overrides ####################################
|
||||
|
||||
# Needed for the `reset_db` management command
|
||||
INSTALLED_APPS += ('django_extensions',)
|
||||
|
||||
# Redirect to the test_root folder within the repo
|
||||
GITHUB_REPO_ROOT = (TEST_ROOT / "data").abspath()
|
||||
LOG_DIR = (TEST_ROOT / "log").abspath()
|
||||
|
||||
# Configure Mongo modulestore to use the test folder within the repo
|
||||
MONGO_MODULESTORE = MODULESTORE['default']['OPTIONS']['stores']['default']
|
||||
MONGO_MODULESTORE['OPTIONS']['fs_root'] = (TEST_ROOT / "data").abspath()
|
||||
|
||||
# Configure XML modulestore to use test root data dir
|
||||
XML_MODULESTORE = MODULESTORE['default']['OPTIONS']['stores']['xml']
|
||||
XML_MODULESTORE['OPTIONS']['data_dir'] = (TEST_ROOT / "data").abspath()
|
||||
|
||||
# Enable django-pipeline and staticfiles
|
||||
STATIC_ROOT = (TEST_ROOT / "staticfiles").abspath()
|
||||
PIPELINE = True
|
||||
|
||||
# Silence noisy logs
|
||||
import logging
|
||||
LOG_OVERRIDES = [
|
||||
('track.middleware', logging.CRITICAL),
|
||||
('edxmako.shortcuts', logging.ERROR),
|
||||
('dd.dogapi', logging.ERROR)
|
||||
]
|
||||
for log_name, log_level in LOG_OVERRIDES:
|
||||
logging.getLogger(log_name).setLevel(log_level)
|
||||
|
||||
# Unfortunately, we need to use debug mode to serve staticfiles
|
||||
DEBUG = True
|
||||
187
rakelib/bok_choy.rake
Normal file
187
rakelib/bok_choy.rake
Normal file
@@ -0,0 +1,187 @@
|
||||
# Run acceptance tests that use the bok-choy framework
|
||||
# http://bok-choy.readthedocs.org/en/latest/
|
||||
require 'dalli'
|
||||
|
||||
|
||||
# Mongo databases that will be dropped before/after the tests run
|
||||
BOK_CHOY_MONGO_DATABASE = "test"
|
||||
|
||||
# Control parallel test execution with environment variables
|
||||
# Process timeout is the maximum amount of time to wait for results from a particular test case
|
||||
BOK_CHOY_NUM_PARALLEL = ENV.fetch('NUM_PARALLEL', 1).to_i
|
||||
BOK_CHOY_TEST_TIMEOUT = ENV.fetch("TEST_TIMEOUT", 300).to_f
|
||||
|
||||
# Ensure that we have a directory to put logs and reports
|
||||
BOK_CHOY_DIR = File.join(REPO_ROOT, "common", "test", "bok_choy")
|
||||
BOK_CHOY_TEST_DIR = File.join(BOK_CHOY_DIR, "tests")
|
||||
BOK_CHOY_LOG_DIR = File.join(REPO_ROOT, "test_root", "log")
|
||||
directory BOK_CHOY_LOG_DIR
|
||||
|
||||
BOK_CHOY_SERVERS = {
|
||||
:lms => { :port => 8003, :log => File.join(BOK_CHOY_LOG_DIR, "bok_choy_lms.log") },
|
||||
:cms => { :port => 8031, :log => File.join(BOK_CHOY_LOG_DIR, "bok_choy_studio.log") }
|
||||
}
|
||||
|
||||
BOK_CHOY_CACHE = Dalli::Client.new('localhost:11211')
|
||||
|
||||
|
||||
# Start the server we will run tests on
|
||||
def start_servers()
|
||||
BOK_CHOY_SERVERS.each do | service, info |
|
||||
address = "0.0.0.0:#{info[:port]}"
|
||||
singleton_process(
|
||||
django_admin(service, 'bok_choy', 'runserver', address),
|
||||
logfile=info[:log]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Wait until we get a successful response from the servers or time out
|
||||
def wait_for_test_servers()
|
||||
BOK_CHOY_SERVERS.each do | service, info |
|
||||
ready = wait_for_server("0.0.0.0", info[:port])
|
||||
if not ready
|
||||
fail("Could not contact #{service} test server")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def is_mongo_running()
|
||||
# The mongo command will connect to the service,
|
||||
# failing with a non-zero exit code if it cannot connect.
|
||||
output = `mongo --eval "print('running')"`
|
||||
return (output and output.include? "running")
|
||||
end
|
||||
|
||||
|
||||
def is_memcache_running()
|
||||
# We use a Ruby memcache client to attempt to set a key
|
||||
# in memcache. If we cannot do so because the service is not
|
||||
# available, then this will raise an exception.
|
||||
BOK_CHOY_CACHE.set('test', 'test')
|
||||
return true
|
||||
rescue Dalli::DalliError
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
def is_mysql_running()
|
||||
# We use the MySQL CLI client and capture its stderr
|
||||
# If the client cannot connect successfully, stderr will be non-empty
|
||||
output = `mysql -e "" 2>&1`
|
||||
return output == ""
|
||||
end
|
||||
|
||||
|
||||
def nose_cmd(test_spec)
|
||||
cmd = ["PYTHONPATH=#{BOK_CHOY_DIR}:$PYTHONPATH", "SCREENSHOT_DIR=#{BOK_CHOY_LOG_DIR}", "nosetests", test_spec]
|
||||
if BOK_CHOY_NUM_PARALLEL > 1
|
||||
cmd += ["--processes=#{BOK_CHOY_NUM_PARALLEL}", "--process-timeout=#{BOK_CHOY_TEST_TIMEOUT}"]
|
||||
end
|
||||
return cmd.join(" ")
|
||||
end
|
||||
|
||||
|
||||
# Run the bok choy tests
|
||||
# `test_spec` is a nose-style test specifier relative to the test directory
|
||||
# Examples:
|
||||
# - path/to/test.py
|
||||
# - path/to/test.py:TestFoo
|
||||
# - path/to/test.py:TestFoo.test_bar
|
||||
# It can also be left blank to run all tests in the suite.
|
||||
def run_bok_choy(test_spec)
|
||||
if test_spec.nil?
|
||||
sh(nose_cmd(BOK_CHOY_TEST_DIR))
|
||||
else
|
||||
sh(nose_cmd(File.join(BOK_CHOY_TEST_DIR, test_spec)))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def clear_mongo()
|
||||
sh("mongo #{BOK_CHOY_MONGO_DATABASE} --eval 'db.dropDatabase()' > /dev/null")
|
||||
end
|
||||
|
||||
|
||||
# Clean up data we created in the databases
|
||||
def cleanup()
|
||||
sh(django_admin('lms', 'bok_choy', 'flush', '--noinput'))
|
||||
clear_mongo()
|
||||
end
|
||||
|
||||
|
||||
namespace :'test:bok_choy' do
|
||||
|
||||
# Check that required services are running
|
||||
task :check_services do
|
||||
if not is_mongo_running()
|
||||
fail("Mongo is not running locally.")
|
||||
end
|
||||
|
||||
if not is_memcache_running()
|
||||
fail("Memcache is not running locally.")
|
||||
end
|
||||
|
||||
if not is_mysql_running()
|
||||
fail("MySQL is not running locally.")
|
||||
end
|
||||
end
|
||||
|
||||
desc "Process assets and set up database for bok-choy tests"
|
||||
task :setup => [:check_services, :install_prereqs, BOK_CHOY_LOG_DIR] do
|
||||
|
||||
# Clear any test data already in Mongo
|
||||
clear_mongo()
|
||||
|
||||
# Invalidate the cache
|
||||
BOK_CHOY_CACHE.flush()
|
||||
|
||||
# HACK: Since the CMS depends on the existence of some database tables
|
||||
# that are now in common but used to be in LMS (Role/Permissions for Forums)
|
||||
# we need to create/migrate the database tables defined in the LMS.
|
||||
# We might be able to address this by moving out the migrations from
|
||||
# lms/django_comment_client, but then we'd have to repair all the existing
|
||||
# migrations from the upgrade tables in the DB.
|
||||
# But for now for either system (lms or cms), use the lms
|
||||
# definitions to sync and migrate.
|
||||
sh(django_admin('lms', 'bok_choy', 'reset_db', '--noinput'))
|
||||
sh(django_admin('lms', 'bok_choy', 'syncdb', '--noinput'))
|
||||
sh(django_admin('lms', 'bok_choy', 'migrate', '--noinput'))
|
||||
|
||||
# Collect static assets
|
||||
Rake::Task["gather_assets"].invoke('lms', 'bok_choy')
|
||||
Rake::Task["gather_assets"].reenable
|
||||
Rake::Task["gather_assets"].invoke('cms', 'bok_choy')
|
||||
end
|
||||
|
||||
desc "Run acceptance tests that use the bok-choy framework but skip setup"
|
||||
task :fast, [:test_spec] => [:check_services, BOK_CHOY_LOG_DIR] do |t, args|
|
||||
|
||||
# Ensure the test servers are available
|
||||
puts "Starting test servers...".red
|
||||
start_servers()
|
||||
puts "Waiting for servers to start...".red
|
||||
wait_for_test_servers()
|
||||
|
||||
begin
|
||||
puts "Running test suite...".red
|
||||
run_bok_choy(args.test_spec)
|
||||
rescue
|
||||
puts "Tests failed!".red
|
||||
exit 1
|
||||
ensure
|
||||
puts "Cleaning up databases...".red
|
||||
cleanup()
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
# Default: set up and run the tests
|
||||
desc "Run acceptance tests that use the bok-choy framework"
|
||||
task :'test:bok_choy', [:test_spec] => [:'test:bok_choy:setup'] do |t, args|
|
||||
Rake::Task["test:bok_choy:fast"].invoke(args.test_spec)
|
||||
end
|
||||
@@ -2,6 +2,7 @@ require 'digest/md5'
|
||||
require 'sys/proctable'
|
||||
require 'colorize'
|
||||
require 'timeout'
|
||||
require 'net/http'
|
||||
|
||||
def find_executable(exec)
|
||||
path = %x(which #{exec}).strip
|
||||
@@ -55,38 +56,28 @@ end
|
||||
def background_process(command, logfile=nil)
|
||||
spawn_opts = {:pgroup => true}
|
||||
if !logfile.nil?
|
||||
puts "Running '#{command.join(' ')}', redirecting output to #{logfile}".red
|
||||
puts "Running '#{command.join(' ')}', redirecting output to #{logfile}"
|
||||
spawn_opts[[:err, :out]] = [logfile, 'a']
|
||||
end
|
||||
pid = Process.spawn({}, *command, spawn_opts)
|
||||
command = [*command]
|
||||
|
||||
at_exit do
|
||||
puts "Ending process and children"
|
||||
pgid = Process.getpgid(pid)
|
||||
begin
|
||||
Timeout.timeout(5) do
|
||||
puts "Interrupting process group #{pgid}"
|
||||
Process.kill(:SIGINT, -pgid)
|
||||
puts "Waiting on process group #{pgid}"
|
||||
Process.wait(-pgid)
|
||||
puts "Done waiting on process group #{pgid}"
|
||||
end
|
||||
rescue Timeout::Error
|
||||
begin
|
||||
Timeout.timeout(5) do
|
||||
puts "Terminating process group #{pgid}"
|
||||
Process.kill(:SIGTERM, -pgid)
|
||||
puts "Waiting on process group #{pgid}"
|
||||
Process.wait(-pgid)
|
||||
puts "Done waiting on process group #{pgid}"
|
||||
end
|
||||
rescue Timeout::Error
|
||||
puts "Killing process group #{pgid}"
|
||||
Process.kill(:SIGKILL, -pgid)
|
||||
puts "Waiting on process group #{pgid}"
|
||||
Process.wait(-pgid)
|
||||
puts "Done waiting on process group #{pgid}"
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -103,6 +94,25 @@ def singleton_process(command, logfile=nil)
|
||||
end
|
||||
end
|
||||
|
||||
# Wait for a server to respond with status 200 at "/"
|
||||
def wait_for_server(server, port)
|
||||
attempts = 0
|
||||
begin
|
||||
http = Net::HTTP.start(server, port, {open_timeout: 10, read_timeout: 10})
|
||||
response = http.head("/")
|
||||
response.code == "200"
|
||||
true
|
||||
rescue
|
||||
sleep(1)
|
||||
attempts += 1
|
||||
if attempts < 20
|
||||
retry
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def environments(system)
|
||||
Dir["#{system}/envs/**/*.py"].select{|file| ! (/__init__.py$/ =~ file)}.map do |env_file|
|
||||
env_file.gsub("#{system}/envs/", '').gsub(/\.py/, '').gsub('/', '.')
|
||||
@@ -135,4 +145,3 @@ if !ENV['TESTS_FAIL_FAST']
|
||||
|
||||
Rake.application.top_level_tasks << :fail_tests
|
||||
end
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ dealer==0.2.3
|
||||
distribute>=0.6.28, <0.7
|
||||
django-celery==3.0.17
|
||||
django-countries==1.5
|
||||
django-extensions==1.2.5
|
||||
django-filter==0.6.0
|
||||
django-followit==0.0.3
|
||||
django-keyedcache==1.4-6
|
||||
|
||||
Reference in New Issue
Block a user