Skip to content

Commit 11e78f8

Browse files
committed
Move sensitive configuration options into separate files
Read credentials for cloud testing services from configuration files in the working or home directory. Fixes pytest-dev#60
1 parent 39cffc1 commit 11e78f8

8 files changed

+207
-129
lines changed

pytest_selenium/drivers/browserstack.py

+22-23
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22
# License, v. 2.0. If a copy of the MPL was not distributed with this
33
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
44

5+
try:
6+
import configparser
7+
except ImportError:
8+
# Python 2.7
9+
import ConfigParser as configparser
10+
511
import os
612

713
import pytest
@@ -12,24 +18,15 @@
1218
EXECUTOR_URL = 'http://{username}:{key}@hub.browserstack.com:80/wd/hub'
1319

1420

15-
def pytest_addoption(parser):
16-
parser.addini('browserstack_username',
17-
help='browserstack username',
18-
default=os.getenv('BROWSERSTACK_USERNAME'))
19-
parser.addini('browserstack_access_key',
20-
help='browserstack access key',
21-
default=os.getenv('BROWSERSTACK_ACCESS_KEY'))
22-
23-
2421
@pytest.mark.optionalhook
2522
def pytest_selenium_runtest_makereport(item, report, summary, extra):
2623
if item.config.getoption('driver') != DRIVER:
2724
return
2825

2926
passed = report.passed or (report.failed and hasattr(report, 'wasxfail'))
3027
session_id = item._driver.session_id
31-
auth = (_username(item.config), _access_key(item.config))
3228
api_url = API_JOB_URL.format(session=session_id)
29+
auth = (credentials()['username'], credentials()['key'])
3330

3431
try:
3532
job_info = requests.get(api_url, auth=auth, timeout=10).json()
@@ -63,24 +60,26 @@ def pytest_selenium_runtest_makereport(item, report, summary, extra):
6360

6461
def driver_kwargs(request, test, capabilities, **kwargs):
6562
capabilities.setdefault('name', test)
66-
executor = EXECUTOR_URL.format(
67-
username=_username(request.config),
68-
key=_access_key(request.config))
63+
executor = EXECUTOR_URL.format(**credentials())
6964
kwargs = {
7065
'command_executor': executor,
7166
'desired_capabilities': capabilities}
7267
return kwargs
7368

7469

75-
def _access_key(config):
76-
access_key = config.getini('browserstack_access_key')
77-
if not access_key:
78-
raise pytest.UsageError('BrowserStack access key must be set')
79-
return access_key
80-
81-
82-
def _username(config):
83-
username = config.getini('browserstack_username')
70+
def credentials():
71+
config = configparser.ConfigParser()
72+
config.read(['.browserstack', os.path.expanduser('~/.browserstack')])
73+
try:
74+
username = config.get('credentials', 'username')
75+
except (configparser.NoSectionError, configparser.NoOptionError, KeyError):
76+
username = os.getenv('BROWSERSTACK_USERNAME')
8477
if not username:
8578
raise pytest.UsageError('BrowserStack username must be set')
86-
return username
79+
try:
80+
key = config.get('credentials', 'key')
81+
except (configparser.NoSectionError, configparser.NoOptionError, KeyError):
82+
key = os.getenv('BROWSERSTACK_ACCESS_KEY')
83+
if not key:
84+
raise pytest.UsageError('BrowserStack access key must be set')
85+
return {'username': username, 'key': key}

pytest_selenium/drivers/crossbrowsertesting.py

+28-30
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22
# License, v. 2.0. If a copy of the MPL was not distributed with this
33
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
44

5+
try:
6+
import configparser
7+
except ImportError:
8+
# Python 2.7
9+
import ConfigParser as configparser
10+
511
import os
612

713
from py.xml import html
@@ -13,23 +19,15 @@
1319
EXECUTOR_URL = 'http://{username}:{key}@hub.crossbrowsertesting.com:80/wd/hub'
1420

1521

16-
def pytest_addoption(parser):
17-
parser.addini('crossbrowsertesting_username',
18-
help='crossbrowsertesting username',
19-
default=os.getenv('CROSSBROWSERTESTING_USERNAME'))
20-
parser.addini('crossbrowsertesting_auth_key',
21-
help='crossbrowsertesting auth key',
22-
default=os.getenv('CROSSBROWSERTESTING_AUTH_KEY'))
23-
24-
2522
@pytest.mark.optionalhook
2623
def pytest_selenium_capture_debug(item, report, extra):
2724
if item.config.getoption('driver') != DRIVER:
2825
return
2926

27+
auth = (credentials()['username'], credentials()['key'])
3028
videos = requests.get(
3129
API_URL.format(session=item._driver.session_id),
32-
auth=_auth(item),
30+
auth=auth,
3331
timeout=10).json().get('videos')
3432

3533
if videos and len(videos) > 0:
@@ -45,9 +43,10 @@ def pytest_selenium_runtest_makereport(item, report, summary, extra):
4543
passed = report.passed or (report.failed and hasattr(report, 'wasxfail'))
4644

4745
# Add the test URL to the summary
46+
auth = (credentials()['username'], credentials()['key'])
4847
info = requests.get(
4948
API_URL.format(session=item._driver.session_id),
50-
auth=_auth(item),
49+
auth=auth,
5150
timeout=10).json()
5251

5352
url = info.get('show_result_public_url')
@@ -65,7 +64,7 @@ def pytest_selenium_runtest_makereport(item, report, summary, extra):
6564
r = requests.put(
6665
API_URL.format(session=info.get('selenium_test_id')),
6766
data=data,
68-
auth=_auth(item),
67+
auth=auth,
6968
timeout=10)
7069
r.raise_for_status()
7170
except Exception as e:
@@ -75,32 +74,31 @@ def pytest_selenium_runtest_makereport(item, report, summary, extra):
7574

7675
def driver_kwargs(request, test, capabilities, **kwargs):
7776
capabilities.setdefault('name', test)
78-
executor = EXECUTOR_URL.format(
79-
username=_username(request.config),
80-
key=_auth_key(request.config))
77+
executor = EXECUTOR_URL.format(**credentials())
8178
kwargs = {
8279
'command_executor': executor,
8380
'desired_capabilities': capabilities}
8481
return kwargs
8582

8683

87-
def _auth_key(config):
88-
auth_key = config.getini('crossbrowsertesting_auth_key')
89-
if not auth_key:
90-
raise pytest.UsageError('CrossBrowserTesting auth key must be set')
91-
return auth_key
92-
93-
94-
def _username(config):
95-
username = config.getini('crossbrowsertesting_username')
84+
def credentials():
85+
config = configparser.ConfigParser()
86+
config.read([
87+
'.crossbrowsertesting',
88+
os.path.expanduser('~/.crossbrowsertesting')])
89+
try:
90+
username = config.get('credentials', 'username')
91+
except (configparser.NoSectionError, configparser.NoOptionError, KeyError):
92+
username = os.getenv('CROSSBROWSERTESTING_USERNAME')
9693
if not username:
9794
raise pytest.UsageError('CrossBrowserTesting username must be set')
98-
return username
99-
100-
101-
def _auth(item):
102-
username = _username(item.config)
103-
return (username, _auth_key(item.config))
95+
try:
96+
key = config.get('credentials', 'key')
97+
except (configparser.NoSectionError, configparser.NoOptionError, KeyError):
98+
key = os.getenv('CROSSBROWSERTESTING_AUTH_KEY')
99+
if not key:
100+
raise pytest.UsageError('CrossBrowserTesting auth key must be set')
101+
return {'username': username, 'key': key}
104102

105103

106104
def _video_html(video):

pytest_selenium/drivers/saucelabs.py

+23-25
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22
# License, v. 2.0. If a copy of the MPL was not distributed with this
33
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
44

5+
try:
6+
import configparser
7+
except ImportError:
8+
# Python 2.7
9+
import ConfigParser as configparser
10+
511
import json
612
import os
713

@@ -16,15 +22,6 @@
1622
JOB_URL = 'http://saucelabs.com/jobs/{session}'
1723

1824

19-
def pytest_addoption(parser):
20-
parser.addini('sauce_labs_username',
21-
help='sauce labs username',
22-
default=os.getenv('SAUCELABS_USERNAME'))
23-
parser.addini('sauce_labs_api_key',
24-
help='sauce labs api key',
25-
default=os.getenv('SAUCELABS_API_KEY'))
26-
27-
2825
@pytest.mark.optionalhook
2926
def pytest_selenium_capture_debug(item, report, extra):
3027
if item.config.getoption('driver') != DRIVER:
@@ -51,9 +48,8 @@ def pytest_selenium_runtest_makereport(item, report, summary, extra):
5148

5249
try:
5350
# Update the job result
54-
username = _username(item.config)
55-
auth = (username, _api_key(item.config))
56-
api_url = API_JOB_URL.format(username=username, session=session_id)
51+
auth = (credentials()['username'], credentials()['key'])
52+
api_url = API_JOB_URL.format(session=session_id, **credentials())
5753
job_info = requests.get(api_url, auth=auth, timeout=10).json()
5854
if report.when == 'setup' or job_info.get('passed') is not False:
5955
# Only update the result if it's not already marked as failed
@@ -71,27 +67,29 @@ def driver_kwargs(request, test, capabilities, **kwargs):
7167
tags = capabilities.get('tags', []) + markers
7268
if tags:
7369
capabilities['tags'] = tags
74-
executor = EXECUTOR_URL.format(
75-
username=_username(request.config),
76-
key=_api_key(request.config))
70+
executor = EXECUTOR_URL.format(**credentials())
7771
kwargs = {
7872
'command_executor': executor,
7973
'desired_capabilities': capabilities}
8074
return kwargs
8175

8276

83-
def _api_key(config):
84-
api_key = config.getini('sauce_labs_api_key')
85-
if not api_key:
86-
raise pytest.UsageError('Sauce Labs API key must be set')
87-
return api_key
88-
89-
90-
def _username(config):
91-
username = config.getini('sauce_labs_username')
77+
def credentials():
78+
config = configparser.ConfigParser()
79+
config.read(['.saucelabs', os.path.expanduser('~/.saucelabs')])
80+
try:
81+
username = config.get('credentials', 'username')
82+
except (configparser.NoSectionError, configparser.NoOptionError, KeyError):
83+
username = os.getenv('SAUCELABS_USERNAME')
9284
if not username:
9385
raise pytest.UsageError('Sauce Labs username must be set')
94-
return username
86+
try:
87+
key = config.get('credentials', 'key')
88+
except (configparser.NoSectionError, configparser.NoOptionError, KeyError):
89+
key = os.getenv('SAUCELABS_API_KEY')
90+
if not key:
91+
raise pytest.UsageError('Sauce Labs API key must be set')
92+
return {'username': username, 'key': key}
9593

9694

9795
def _video_html(session):

pytest_selenium/drivers/testingbot.py

+20-21
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22
# License, v. 2.0. If a copy of the MPL was not distributed with this
33
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
44

5+
try:
6+
import configparser
7+
except ImportError:
8+
# Python 2.7
9+
import ConfigParser as configparser
10+
511
import os
612

713
import pytest
@@ -15,15 +21,6 @@
1521
JOB_URL = 'http://testingbot.com/members/tests/{session}'
1622

1723

18-
def pytest_addoption(parser):
19-
parser.addini('testingbot_key',
20-
help='testingbot key',
21-
default=os.getenv('TESTINGBOT_KEY'))
22-
parser.addini('testingbot_secret',
23-
help='testingbot secret',
24-
default=os.getenv('TESTINGBOT_SECRET'))
25-
26-
2724
@pytest.mark.optionalhook
2825
def pytest_selenium_capture_debug(item, report, extra):
2926
if item.config.getoption('driver') != DRIVER:
@@ -50,7 +47,7 @@ def pytest_selenium_runtest_makereport(item, report, summary, extra):
5047

5148
try:
5249
# Update the job result
53-
auth = (_key(item.config), _secret(item.config))
50+
auth = (credentials()['key'], credentials()['secret'])
5451
api_url = API_JOB_URL.format(session=session_id)
5552
job_info = requests.get(api_url, auth=auth, timeout=10).json()
5653
if report.when == 'setup' or job_info.get('success') is not False:
@@ -69,27 +66,29 @@ def driver_kwargs(request, test, capabilities, **kwargs):
6966
groups = capabilities.get('groups', []) + markers
7067
if groups:
7168
capabilities['groups'] = groups
72-
executor = EXECUTOR_URL.format(
73-
key=_key(request.config),
74-
secret=_secret(request.config))
69+
executor = EXECUTOR_URL.format(**credentials())
7570
kwargs = {
7671
'command_executor': executor,
7772
'desired_capabilities': capabilities}
7873
return kwargs
7974

8075

81-
def _key(config):
82-
key = config.getini('testingbot_key')
76+
def credentials():
77+
config = configparser.ConfigParser()
78+
config.read(['.testingbot', os.path.expanduser('~/.testingbot')])
79+
try:
80+
key = config.get('credentials', 'key')
81+
except (configparser.NoSectionError, configparser.NoOptionError, KeyError):
82+
key = os.getenv('TESTINGBOT_KEY')
8383
if not key:
8484
raise pytest.UsageError('TestingBot key must be set')
85-
return key
86-
87-
88-
def _secret(config):
89-
secret = config.getini('testingbot_secret')
85+
try:
86+
secret = config.get('credentials', 'secret')
87+
except (configparser.NoSectionError, configparser.NoOptionError, KeyError):
88+
secret = os.getenv('TESTINGBOT_SECRET')
9089
if not secret:
9190
raise pytest.UsageError('TestingBot secret must be set')
92-
return secret
91+
return {'key': key, 'secret': secret}
9392

9493

9594
def _video_html(session):

0 commit comments

Comments
 (0)