Commit 8c3d4ce8 by Calen Pennington

Split actions needed for bok_choy tests into smaller tasks to get more granular timing information

parent fa525732
......@@ -4,6 +4,7 @@ Acceptance test tasks
from paver.easy import cmdopts, needs
from pavelib.utils.test.suites import AcceptanceTestSuite
from pavelib.utils.passthrough_opts import PassthroughTask
from pavelib.utils.timer import timed
from optparse import make_option
try:
......@@ -29,6 +30,7 @@ __test__ = False # do not collect
('extra_args=', 'e', 'deprecated, pass extra options directly in the paver commandline'),
])
@PassthroughTask
@timed
def test_acceptance(options, passthrough_options):
"""
Run the acceptance tests for either lms or cms
......
......@@ -71,10 +71,12 @@ def test_a11y(options, passthrough_options):
It can also be left blank to run all tests in the suite that are tagged
with `@attr("a11y")`.
"""
# Modify the options object directly, so that any subsequently called tasks
# that share with this task get the modified options
options['report_dir'] = Env.BOK_CHOY_A11Y_REPORT_DIR
options['coveragerc'] = Env.BOK_CHOY_A11Y_COVERAGERC
options['extra_args'] = options.get('extra_args', '') + ' -a "a11y" '
opts = parse_bokchoy_opts(options, passthrough_options)
opts['report_dir'] = Env.BOK_CHOY_A11Y_REPORT_DIR
opts['coveragerc'] = Env.BOK_CHOY_A11Y_COVERAGERC
opts['extra_args'] = opts['extra_args'] + ' -a "a11y" '
run_bokchoy(**opts)
......@@ -86,8 +88,10 @@ def perf_report_bokchoy(options, passthrough_options):
"""
Generates a har file for with page performance info.
"""
# Modify the options object directly, so that any subsequently called tasks
# that share with this task get the modified options
options['test_dir'] = 'performance'
opts = parse_bokchoy_opts(options, passthrough_options)
opts['test_dir'] = 'performance'
run_bokchoy(**opts)
......@@ -114,11 +118,13 @@ def pa11ycrawler(options, passthrough_options):
flag to get an environment running. The setup for this is the same as
for bok-choy tests, only test course is imported as well.
"""
# Modify the options object directly, so that any subsequently called tasks
# that share with this task get the modified options
options['report_dir'] = Env.PA11YCRAWLER_REPORT_DIR
options['coveragerc'] = Env.PA11YCRAWLER_COVERAGERC
options['should_fetch_course'] = getattr(options, 'should_fetch_course', not options.get('fasttest'))
options['course_key'] = getattr(options, 'course-key', "course-v1:edX+Test101+course")
opts = parse_bokchoy_opts(options, passthrough_options)
opts['report_dir'] = Env.PA11YCRAWLER_REPORT_DIR
opts['coveragerc'] = Env.PA11YCRAWLER_COVERAGERC
opts['should_fetch_course'] = getattr(options, 'should_fetch_course', not opts['fasttest'])
opts['course_key'] = getattr(options, 'course-key', "course-v1:edX+Test101+course")
test_suite = Pa11yCrawler('a11y_crawler', **opts)
test_suite.run()
......
......@@ -64,5 +64,6 @@ def parse_bokchoy_opts(options, passthrough_options=None):
'test_dir': getattr(options, 'test_dir', 'tests'),
'imports_dir': getattr(options, 'imports_dir', None),
'save_screenshots': getattr(options, 'save_screenshots', False),
'passthrough_options': passthrough_options
'passthrough_options': passthrough_options,
'report_dir': getattr(options, 'report_dir', Env.BOK_CHOY_REPORT_DIR),
}
......@@ -6,9 +6,11 @@ import os
import time
import httplib
import subprocess
from paver.easy import sh
from paver.easy import sh, task, cmdopts
from pavelib.utils.envs import Env
from pavelib.utils.process import run_background_process
from pavelib.utils.test.bokchoy_options import BOKCHOY_OPTS
from pavelib.utils.timer import timed
try:
from pygments.console import colorize
......@@ -18,11 +20,14 @@ except ImportError:
__test__ = False # do not collect
def start_servers(default_store, coveragerc=None):
@task
@cmdopts(BOKCHOY_OPTS, share_with=['test_bokchoy', 'test_a11y', 'pa11ycrawler'])
@timed
def start_servers(options):
"""
Start the servers we will run tests on, returns PIDs for servers.
"""
coveragerc = coveragerc or Env.BOK_CHOY_COVERAGERC
coveragerc = options.get('coveragerc', Env.BOK_CHOY_COVERAGERC)
def start_server(cmd, logfile, cwd=None):
"""
......@@ -38,7 +43,7 @@ def start_servers(default_store, coveragerc=None):
"coverage run --rcfile={coveragerc} -m "
"manage {service} --settings bok_choy runserver "
"{address} --traceback --noreload".format(
default_store=default_store,
default_store=options.default_store,
coveragerc=coveragerc,
service=service,
address=address,
......@@ -137,6 +142,8 @@ def is_mysql_running():
return returncode == 0
@task
@timed
def clear_mongo():
"""
Clears mongo database.
......@@ -148,6 +155,8 @@ def clear_mongo():
)
@task
@timed
def check_mongo():
"""
Check that mongo is running
......@@ -158,6 +167,8 @@ def check_mongo():
sys.exit(1)
@task
@timed
def check_memcache():
"""
Check that memcache is running
......@@ -168,6 +179,8 @@ def check_memcache():
sys.exit(1)
@task
@timed
def check_mysql():
"""
Check that mysql is running
......@@ -178,6 +191,8 @@ def check_mysql():
sys.exit(1)
@task
@timed
def check_services():
"""
Check that all required services are running
......
"""
Acceptance test suite
"""
from paver.easy import sh, call_task
from paver.easy import sh, call_task, task
from pavelib.utils.test import utils as test_utils
from pavelib.utils.test.suites.suite import TestSuite
from pavelib.utils.envs import Env
from pavelib.utils.timer import timed
__test__ = False # do not collect
DBS = {
'default': Env.REPO_ROOT / 'test_root/db/test_edx.db',
'student_module_history': Env.REPO_ROOT / 'test_root/db/test_student_module_history.db'
}
DB_CACHES = {
'default': Env.REPO_ROOT / 'common/test/db_cache/lettuce.db',
'student_module_history': Env.REPO_ROOT / 'common/test/db_cache/lettuce_student_module_history.db'
}
@task
@timed
def setup_acceptance_db():
"""
TODO: Improve the following
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.
"""
for db in DBS.keys():
if DBS[db].isfile():
# Since we are using SQLLite, we can reset the database by deleting it on disk.
DBS[db].remove()
if all(DB_CACHES[cache].isfile() for cache in DB_CACHES.keys()):
# To speed up migrations, we check for a cached database file and start from that.
# The cached database file should be checked into the repo
# Copy the cached database to the test root directory
for db_alias in DBS.keys():
sh("cp {db_cache} {db}".format(db_cache=DB_CACHES[db_alias], db=DBS[db_alias]))
# Run migrations to update the db, starting from its cached state
for db_alias in sorted(DBS.keys()):
# pylint: disable=line-too-long
sh("./manage.py lms --settings acceptance migrate --traceback --noinput --fake-initial --database {}".format(db_alias))
sh("./manage.py cms --settings acceptance migrate --traceback --noinput --fake-initial --database {}".format(db_alias))
else:
# If no cached database exists, syncdb before migrating, then create the cache
for db_alias in sorted(DBS.keys()):
sh("./manage.py lms --settings acceptance migrate --traceback --noinput --database {}".format(db_alias))
sh("./manage.py cms --settings acceptance migrate --traceback --noinput --database {}".format(db_alias))
# Create the cache if it doesn't already exist
for db_alias in DBS.keys():
sh("cp {db} {db_cache}".format(db_cache=DB_CACHES[db_alias], db=DBS[db_alias]))
class AcceptanceTest(TestSuite):
"""
A class for running lettuce acceptance tests.
......@@ -67,14 +123,6 @@ class AcceptanceTestSuite(TestSuite):
def __init__(self, *args, **kwargs):
super(AcceptanceTestSuite, self).__init__(*args, **kwargs)
self.root = 'acceptance'
self.dbs = {
'default': Env.REPO_ROOT / 'test_root/db/test_edx.db',
'student_module_history': Env.REPO_ROOT / 'test_root/db/test_student_module_history.db'
}
self.db_caches = {
'default': Env.REPO_ROOT / 'common/test/db_cache/lettuce.db',
'student_module_history': Env.REPO_ROOT / 'common/test/db_cache/lettuce_student_module_history.db'
}
self.fasttest = kwargs.get('fasttest', False)
if kwargs.get('system'):
......@@ -102,46 +150,4 @@ class AcceptanceTestSuite(TestSuite):
test_utils.clean_test_files()
if not self.fasttest:
self._setup_acceptance_db()
def _setup_acceptance_db(self):
"""
TODO: Improve the following
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.
"""
for db in self.dbs.keys():
if self.dbs[db].isfile():
# Since we are using SQLLite, we can reset the database by deleting it on disk.
self.dbs[db].remove()
if all(self.db_caches[cache].isfile() for cache in self.db_caches.keys()):
# To speed up migrations, we check for a cached database file and start from that.
# The cached database file should be checked into the repo
# Copy the cached database to the test root directory
for db_alias in self.dbs.keys():
sh("cp {db_cache} {db}".format(db_cache=self.db_caches[db_alias], db=self.dbs[db_alias]))
# Run migrations to update the db, starting from its cached state
for db_alias in sorted(self.dbs.keys()):
# pylint: disable=line-too-long
sh("./manage.py lms --settings acceptance migrate --traceback --noinput --fake-initial --database {}".format(db_alias))
sh("./manage.py cms --settings acceptance migrate --traceback --noinput --fake-initial --database {}".format(db_alias))
else:
# If no cached database exists, syncdb before migrating, then create the cache
for db_alias in sorted(self.dbs.keys()):
sh("./manage.py lms --settings acceptance migrate --traceback --noinput --database {}".format(db_alias))
sh("./manage.py cms --settings acceptance migrate --traceback --noinput --database {}".format(db_alias))
# Create the cache if it doesn't already exist
for db_alias in self.dbs.keys():
sh("cp {db} {db_cache}".format(db_cache=self.db_caches[db_alias], db=self.dbs[db_alias]))
setup_acceptance_db()
......@@ -7,11 +7,15 @@ from urllib import urlencode
from common.test.acceptance.fixtures.course import CourseFixture, FixtureError
from path import Path as path
from paver.easy import sh, BuildFailure
from paver.easy import sh, BuildFailure, cmdopts, task, needs
from pavelib.utils.test.suites.suite import TestSuite
from pavelib.utils.envs import Env
from pavelib.utils.test import bokchoy_utils
from pavelib.utils.test.bokchoy_utils import (
clear_mongo, start_servers, check_services, wait_for_test_servers
)
from pavelib.utils.test.bokchoy_options import BOKCHOY_OPTS
from pavelib.utils.test import utils as test_utils
from pavelib.utils.timer import timed
import os
......@@ -26,6 +30,77 @@ DEFAULT_NUM_PROCESSES = 1
DEFAULT_VERBOSITY = 2
@task
@cmdopts(BOKCHOY_OPTS, share_with=['test_bokchoy', 'test_a11y', 'pa11ycrawler'])
@timed
def load_bok_choy_data(options):
"""
Loads data into database from db_fixtures
"""
print 'Loading data from json fixtures in db_fixtures directory'
sh(
"DEFAULT_STORE={default_store}"
" ./manage.py lms --settings bok_choy loaddata --traceback"
" common/test/db_fixtures/*.json".format(
default_store=options.default_store,
)
)
@task
@cmdopts(BOKCHOY_OPTS, share_with=['test_bokchoy', 'test_a11y', 'pa11ycrawler'])
@timed
def load_courses(options):
"""
Loads courses from options.imports_dir.
Note: options.imports_dir is the directory that contains the directories
that have courses in them. For example, if the course is located in
`test_root/courses/test-example-course/`, options.imports_dir should be
`test_root/courses/`.
"""
if 'imports_dir' in options:
msg = colorize('green', "Importing courses from {}...".format(options.imports_dir))
print msg
sh(
"DEFAULT_STORE={default_store}"
" ./manage.py cms --settings=bok_choy import {import_dir}".format(
default_store=options.default_store,
import_dir=options.imports_dir
)
)
@task
@timed
def reset_test_database():
"""
Reset the database used by the bokchoy tests.
"""
sh("{}/scripts/reset-test-db.sh".format(Env.REPO_ROOT))
@task
@needs(['reset_test_database', 'clear_mongo', 'load_bok_choy_data', 'load_courses'])
@cmdopts(BOKCHOY_OPTS, share_with=['test_bokchoy', 'test_a11y', 'pa11ycrawler'])
@timed
def prepare_bokchoy_run(options, call_task):
"""
Sets up and starts servers for a Bok Choy run. If --fasttest is not
specified then static assets are collected
"""
if not options.get('fasttest', False):
print colorize('green', "Generating optimized static assets...")
# Use call_task so that we can specify options
call_task('update_assets', args=['--settings', 'test_static_optimized'])
# Ensure the test servers are available
msg = colorize('green', "Confirming servers are running...")
print msg
start_servers() # pylint: disable=no-value-for-parameter
class BokChoyTestSuite(TestSuite):
"""
TestSuite for running Bok Choy tests
......@@ -80,17 +155,17 @@ class BokChoyTestSuite(TestSuite):
msg = colorize('green', "Checking for mongo, memchache, and mysql...")
print msg
bokchoy_utils.check_services()
check_services()
if not self.testsonly:
self.prepare_bokchoy_run()
prepare_bokchoy_run() # pylint: disable=no-value-for-parameter
else:
# load data in db_fixtures
self.load_data()
load_bok_choy_data() # pylint: disable=no-value-for-parameter
msg = colorize('green', "Confirming servers have started...")
print msg
bokchoy_utils.wait_for_test_servers()
wait_for_test_servers()
try:
# Create course in order to seed forum data underneath. This is
# a workaround for a race condition. The first time a course is created;
......@@ -116,7 +191,7 @@ class BokChoyTestSuite(TestSuite):
msg = colorize('green', "Cleaning up databases...")
print msg
sh("./manage.py lms --settings bok_choy flush --traceback --noinput")
bokchoy_utils.clear_mongo()
clear_mongo()
@property
def verbosity_processes_command(self):
......@@ -147,66 +222,6 @@ class BokChoyTestSuite(TestSuite):
return command
def prepare_bokchoy_run(self):
"""
Sets up and starts servers for a Bok Choy run. If --fasttest is not
specified then static assets are collected
"""
sh("{}/scripts/reset-test-db.sh".format(Env.REPO_ROOT))
if not self.fasttest:
self.generate_optimized_static_assets()
# Clear any test data already in Mongo or MySQLand invalidate
# the cache
bokchoy_utils.clear_mongo()
self.cache.flush_all()
# load data in db_fixtures
self.load_data()
# load courses if self.imports_dir is set
self.load_courses()
# Ensure the test servers are available
msg = colorize('green', "Confirming servers are running...")
print msg
bokchoy_utils.start_servers(self.default_store, self.coveragerc)
def load_courses(self):
"""
Loads courses from self.imports_dir.
Note: self.imports_dir is the directory that contains the directories
that have courses in them. For example, if the course is located in
`test_root/courses/test-example-course/`, self.imports_dir should be
`test_root/courses/`.
"""
msg = colorize('green', "Importing courses from {}...".format(self.imports_dir))
print msg
if 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
)
)
def load_data(self):
"""
Loads data into database from db_fixtures
"""
print 'Loading data from json fixtures in db_fixtures directory'
sh(
"DEFAULT_STORE={default_store}"
" ./manage.py lms --settings bok_choy loaddata --traceback"
" common/test/db_fixtures/*.json".format(
default_store=self.default_store,
)
)
def run_servers_continuously(self):
"""
Infinite loop. Servers will continue to run in the current session unless interrupted.
......
......@@ -61,14 +61,6 @@ class TestSuite(object):
"""
return None
def generate_optimized_static_assets(self):
"""
Collect static assets using test_static_optimized.py which generates
optimized files to a dedicated test static root.
"""
print colorize('green', "Generating optimized static assets...")
sh("paver update_assets --settings=test_static_optimized")
def run_test(self):
"""
Runs a self.cmd in a subprocess and waits for it to finish.
......
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