Commit da538b87 by Jay Zoldak

Merge pull request #1044 from edx/zoldak/acceptance-grid

Add ability to run against generic selenium grid
parents 1d2e0b66 4c411e21
...@@ -84,12 +84,26 @@ USE_I18N = True ...@@ -84,12 +84,26 @@ USE_I18N = True
# Include the lettuce app for acceptance testing, including the 'harvest' django-admin command # Include the lettuce app for acceptance testing, including the 'harvest' django-admin command
INSTALLED_APPS += ('lettuce.django',) INSTALLED_APPS += ('lettuce.django',)
LETTUCE_APPS = ('contentstore',) LETTUCE_APPS = ('contentstore',)
LETTUCE_SERVER_PORT = choice(PORTS) if SAUCE.get('SAUCE_ENABLED') else randint(1024, 65535)
LETTUCE_BROWSER = os.environ.get('LETTUCE_BROWSER', 'chrome') LETTUCE_BROWSER = os.environ.get('LETTUCE_BROWSER', 'chrome')
# Where to run: local, saucelabs, or grid
LETTUCE_SELENIUM_CLIENT = os.environ.get('LETTUCE_SELENIUM_CLIENT', 'local')
SELENIUM_GRID = {
'URL': 'http://127.0.0.1:4444/wd/hub',
'BROWSER': LETTUCE_BROWSER,
}
##################################################################### #####################################################################
# Lastly, see if the developer has any local overrides. # Lastly, see if the developer has any local overrides.
try: try:
from .private import * # pylint: disable=F0401 from .private import * # pylint: disable=F0401
except ImportError: except ImportError:
pass pass
# Because an override for where to run will affect which ports to use,
# set this up after the local overrides.
if LETTUCE_SELENIUM_CLIENT == 'saucelabs':
LETTUCE_SERVER_PORT = choice(PORTS)
else:
LETTUCE_SERVER_PORT = randint(1024, 65535)
...@@ -43,18 +43,18 @@ LOGGER.info("Loading the lettuce acceptance testing terrain file...") ...@@ -43,18 +43,18 @@ LOGGER.info("Loading the lettuce acceptance testing terrain file...")
MAX_VALID_BROWSER_ATTEMPTS = 20 MAX_VALID_BROWSER_ATTEMPTS = 20
def get_username_and_key(): def get_saucelabs_username_and_key():
""" """
Returns the Sauce Labs username and access ID as set by environment variables Returns the Sauce Labs username and access ID as set by environment variables
""" """
return {"username": settings.SAUCE.get('USERNAME'), "access-key": settings.SAUCE.get('ACCESS_ID')} return {"username": settings.SAUCE.get('USERNAME'), "access-key": settings.SAUCE.get('ACCESS_ID')}
def set_job_status(jobid, passed=True): def set_saucelabs_job_status(jobid, passed=True):
""" """
Sets the job status on sauce labs Sets the job status on sauce labs
""" """
config = get_username_and_key() config = get_saucelabs_username_and_key()
url = 'http://saucelabs.com/rest/v1/{}/jobs/{}'.format(config['username'], world.jobid) url = 'http://saucelabs.com/rest/v1/{}/jobs/{}'.format(config['username'], world.jobid)
body_content = dumps({"passed": passed}) body_content = dumps({"passed": passed})
base64string = encodestring('{}:{}'.format(config['username'], config['access-key']))[:-1] base64string = encodestring('{}:{}'.format(config['username'], config['access-key']))[:-1]
...@@ -63,7 +63,7 @@ def set_job_status(jobid, passed=True): ...@@ -63,7 +63,7 @@ def set_job_status(jobid, passed=True):
return result.status_code == 200 return result.status_code == 200
def make_desired_capabilities(): def make_saucelabs_desired_capabilities():
""" """
Returns a DesiredCapabilities object corresponding to the environment sauce parameters Returns a DesiredCapabilities object corresponding to the environment sauce parameters
""" """
...@@ -88,9 +88,9 @@ def initial_setup(server): ...@@ -88,9 +88,9 @@ def initial_setup(server):
""" """
Launch the browser once before executing the tests. Launch the browser once before executing the tests.
""" """
world.absorb(settings.SAUCE.get('SAUCE_ENABLED'), 'SAUCE_ENABLED') world.absorb(settings.LETTUCE_SELENIUM_CLIENT, 'LETTUCE_SELENIUM_CLIENT')
if not world.SAUCE_ENABLED: if world.LETTUCE_SELENIUM_CLIENT == 'local':
browser_driver = getattr(settings, 'LETTUCE_BROWSER', 'chrome') browser_driver = getattr(settings, 'LETTUCE_BROWSER', 'chrome')
# There is an issue with ChromeDriver2 r195627 on Ubuntu # There is an issue with ChromeDriver2 r195627 on Ubuntu
...@@ -121,15 +121,26 @@ def initial_setup(server): ...@@ -121,15 +121,26 @@ def initial_setup(server):
world.browser.driver.set_window_size(1280, 1024) world.browser.driver.set_window_size(1280, 1024)
else: elif world.LETTUCE_SELENIUM_CLIENT == 'saucelabs':
config = get_username_and_key() config = get_saucelabs_username_and_key()
world.browser = Browser( world.browser = Browser(
'remote', 'remote',
url="http://{}:{}@ondemand.saucelabs.com:80/wd/hub".format(config['username'], config['access-key']), url="http://{}:{}@ondemand.saucelabs.com:80/wd/hub".format(config['username'], config['access-key']),
**make_desired_capabilities() **make_saucelabs_desired_capabilities()
)
world.browser.driver.implicitly_wait(30)
elif world.LETTUCE_SELENIUM_CLIENT == 'grid':
world.browser = Browser(
'remote',
url=settings.SELENIUM_GRID.get('URL'),
browser=settings.SELENIUM_GRID.get('BROWSER'),
) )
world.browser.driver.implicitly_wait(30) world.browser.driver.implicitly_wait(30)
else:
raise Exception("Unknown selenium client '{}'".format(world.LETTUCE_SELENIUM_CLIENT))
world.absorb(world.browser.driver.session_id, 'jobid') world.absorb(world.browser.driver.session_id, 'jobid')
...@@ -183,6 +194,6 @@ def teardown_browser(total): ...@@ -183,6 +194,6 @@ def teardown_browser(total):
""" """
Quit the browser after executing the tests. Quit the browser after executing the tests.
""" """
if world.SAUCE_ENABLED: if world.LETTUCE_SELENIUM_CLIENT == 'saucelabs':
set_job_status(world.jobid, total.scenarios_ran == total.scenarios_passed) set_saucelabs_job_status(world.jobid, total.scenarios_ran == total.scenarios_passed)
world.browser.quit() world.browser.quit()
...@@ -138,9 +138,10 @@ def should_have_link_with_path_and_text(step, path, text): ...@@ -138,9 +138,10 @@ def should_have_link_with_path_and_text(step, path, text):
@step(r'should( not)? see "(.*)" (?:somewhere|anywhere) (?:in|on) (?:the|this) page') @step(r'should( not)? see "(.*)" (?:somewhere|anywhere) (?:in|on) (?:the|this) page')
def should_see_in_the_page(step, doesnt_appear, text): def should_see_in_the_page(step, doesnt_appear, text):
multiplier = 1 if world.LETTUCE_SELENIUM_CLIENT == 'saucelabs':
if world.SAUCE_ENABLED:
multiplier = 2 multiplier = 2
else:
multiplier = 1
if doesnt_appear: if doesnt_appear:
assert world.browser.is_text_not_present(text, wait_time=5*multiplier) assert world.browser.is_text_not_present(text, wait_time=5*multiplier)
else: else:
......
...@@ -36,7 +36,7 @@ SKIP_TESTS="" ...@@ -36,7 +36,7 @@ SKIP_TESTS=""
if [ ! -z ${LETTUCE_BROWSER+x} ]; then if [ ! -z ${LETTUCE_BROWSER+x} ]; then
SKIP_TESTS="--tag -skip_$LETTUCE_BROWSER" SKIP_TESTS="--tag -skip_$LETTUCE_BROWSER"
fi fi
if [ ! -z ${SAUCE_ENABLED+x} ]; then if [ "$LETTUCE_SELENIUM_CLIENT" == saucelabs ]; then
# SAUCE_INFO is a - seperated string PLATFORM-BROWSER-VERSION-DEVICE # SAUCE_INFO is a - seperated string PLATFORM-BROWSER-VERSION-DEVICE
# Error checking is done in the setting up of the browser # Error checking is done in the setting up of the browser
IFS='-' read -a SAUCE <<< "${SAUCE_INFO}" IFS='-' read -a SAUCE <<< "${SAUCE_INFO}"
......
...@@ -71,23 +71,6 @@ DATABASES = { ...@@ -71,23 +71,6 @@ DATABASES = {
} }
} }
# Set up XQueue information so that the lms will send
# requests to a mock XQueue server running locally
XQUEUE_PORT = choice(PORTS) if SAUCE.get('SAUCE_ENABLED') else randint(1024, 65535)
XQUEUE_INTERFACE = {
"url": "http://127.0.0.1:%d" % XQUEUE_PORT,
"django_auth": {
"username": "lms",
"password": "***REMOVED***"
},
"basic_auth": ('anant', 'agarwal'),
}
# Set up Video information so that the lms will send
# requests to a mock Youtube server running locally
VIDEO_PORT = XQUEUE_PORT + 2
# Forums are disabled in test.py to speed up unit tests, but we do not have # Forums are disabled in test.py to speed up unit tests, but we do not have
# per-test control for acceptance tests # per-test control for acceptance tests
MITX_FEATURES['ENABLE_DISCUSSION_SERVICE'] = True MITX_FEATURES['ENABLE_DISCUSSION_SERVICE'] = True
...@@ -123,12 +106,52 @@ FEEDBACK_SUBMISSION_EMAIL = 'dummy@example.com' ...@@ -123,12 +106,52 @@ FEEDBACK_SUBMISSION_EMAIL = 'dummy@example.com'
# Include the lettuce app for acceptance testing, including the 'harvest' django-admin command # Include the lettuce app for acceptance testing, including the 'harvest' django-admin command
INSTALLED_APPS += ('lettuce.django',) INSTALLED_APPS += ('lettuce.django',)
LETTUCE_APPS = ('courseware',) LETTUCE_APPS = ('courseware',)
LETTUCE_SERVER_PORT = choice(PORTS) if SAUCE.get('SAUCE_ENABLED') else randint(1024, 65535)
LETTUCE_BROWSER = os.environ.get('LETTUCE_BROWSER', 'chrome') LETTUCE_BROWSER = os.environ.get('LETTUCE_BROWSER', 'chrome')
# Where to run: local, saucelabs, or grid
LETTUCE_SELENIUM_CLIENT = os.environ.get('LETTUCE_SELENIUM_CLIENT', 'local')
SELENIUM_GRID = {
'URL': 'http://127.0.0.1:4444/wd/hub',
'BROWSER': LETTUCE_BROWSER,
}
##################################################################### #####################################################################
# Lastly, see if the developer has any local overrides. # See if the developer has any local overrides.
try: try:
from .private import * # pylint: disable=F0401 from .private import * # pylint: disable=F0401
except ImportError: except ImportError:
pass pass
# Because an override for where to run will affect which ports to use,
# set these up after the local overrides.
if LETTUCE_SELENIUM_CLIENT == 'saucelabs':
LETTUCE_SERVER_PORT = choice(PORTS)
PORTS.remove(LETTUCE_SERVER_PORT)
else:
LETTUCE_SERVER_PORT = randint(1024, 65535)
# Set up XQueue information so that the lms will send
# requests to a mock XQueue server running locally
if LETTUCE_SELENIUM_CLIENT == 'saucelabs':
XQUEUE_PORT = choice(PORTS)
PORTS.remove(XQUEUE_PORT)
else:
XQUEUE_PORT = randint(1024, 65535)
XQUEUE_INTERFACE = {
"url": "http://127.0.0.1:%d" % XQUEUE_PORT,
"django_auth": {
"username": "lms",
"password": "***REMOVED***"
},
"basic_auth": ('anant', 'agarwal'),
}
# Set up Video information so that the lms will send
# requests to a mock Youtube server running locally
if LETTUCE_SELENIUM_CLIENT == 'saucelabs':
VIDEO_PORT = choice(PORTS)
PORTS.remove(VIDEO_PORT)
else:
VIDEO_PORT = randint(1024, 65535)
...@@ -51,7 +51,6 @@ SAUCE_INFO = ALL_CONFIG.get(os.environ.get('SAUCE_INFO', 'Linux-chrome--')) ...@@ -51,7 +51,6 @@ SAUCE_INFO = ALL_CONFIG.get(os.environ.get('SAUCE_INFO', 'Linux-chrome--'))
# Information needed to utilize Sauce Labs. # Information needed to utilize Sauce Labs.
SAUCE = { SAUCE = {
'SAUCE_ENABLED': os.environ.get('SAUCE_ENABLED'),
'USERNAME': os.environ.get('SAUCE_USER_NAME'), 'USERNAME': os.environ.get('SAUCE_USER_NAME'),
'ACCESS_ID': os.environ.get('SAUCE_API_KEY'), 'ACCESS_ID': os.environ.get('SAUCE_API_KEY'),
'PLATFORM': SAUCE_INFO[0], 'PLATFORM': SAUCE_INFO[0],
......
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