Merge pull request #218 from mesosphere/windows_integration_tests

[ADD] DCOS-1002  Create a TeamCity integrated test for Windows version of DCOS CLI
This commit is contained in:
ytalashkocv
2015-06-23 12:45:52 +03:00
19 changed files with 292 additions and 76 deletions

View File

@@ -30,7 +30,9 @@ def exec_command(cmd, env=None, stdin=None):
stderr=subprocess.PIPE,
env=env)
stdout, stderr = process.communicate()
# This is needed to get rid of '\r' from Windows's lines endings.
stdout, stderr = [std_stream.replace(b'\r', b'')
for std_stream in process.communicate()]
# We should always print the stdout and stderr
print('STDOUT: {}'.format(_truncate(stdout.decode('utf-8'))))

View File

@@ -35,6 +35,64 @@ def _mock(fn):
return wrapper
@_mock
def test_production_setting_true():
'''Test that env var DCOS_PRODUCTION as empty string sends exceptions
to the 'prod' environment.
'''
args = [util.which('dcos')]
env = _env_reporting()
env['DCOS_PRODUCTION'] = ''
with patch('sys.argv', args), patch.dict(os.environ, env):
assert main() == 0
_, kwargs = requests.post.call_args_list[0]
assert kwargs['auth'].username == SEGMENT_IO_WRITE_KEY_PROD
rollbar.init.assert_called_with(ROLLBAR_SERVER_POST_KEY, 'prod')
@_mock
def test_production_setting_false():
'''Test that env var DCOS_PRODUCTION=false sends exceptions to
the 'dev' environment.
'''
args = [util.which('dcos')]
env = _env_reporting()
env['DCOS_PRODUCTION'] = 'false'
with patch('sys.argv', args), patch.dict(os.environ, env):
assert main() == 0
_, kwargs = requests.post.call_args_list[0]
assert kwargs['auth'].username == SEGMENT_IO_WRITE_KEY_DEV
rollbar.init.assert_called_with(ROLLBAR_SERVER_POST_KEY, 'dev')
@_mock
def test_config_set():
'''Tests that a `dcos config set core.email <email>` makes a
segment.io identify call'''
args = [util.which('dcos'), 'config', 'set', 'core.email', 'test@mail.com']
env = _env_reporting()
with patch('sys.argv', args), patch.dict(os.environ, env):
assert config_main() == 0
# segment.io
assert mock_called_some_args(requests.post,
'{}/identify'.format(SEGMENT_URL),
json={'userId': 'test@mail.com'},
timeout=1)
@_mock
def test_no_exc():
'''Tests that a command which does not raise an exception does not
@@ -115,64 +173,6 @@ def test_config_reporting_false():
assert requests.post.call_count == 0
@_mock
def test_production_setting_true():
'''Test that env var DCOS_PRODUCTION as empty string sends exceptions
to the 'prod' environment.
'''
args = [util.which('dcos')]
env = _env_reporting()
env['DCOS_PRODUCTION'] = ''
with patch('sys.argv', args), patch.dict(os.environ, env):
assert main() == 0
_, kwargs = requests.post.call_args_list[0]
assert kwargs['auth'].username == SEGMENT_IO_WRITE_KEY_PROD
rollbar.init.assert_called_with(ROLLBAR_SERVER_POST_KEY, 'prod')
@_mock
def test_production_setting_false():
'''Test that env var DCOS_PRODUCTION=false sends exceptions to
the 'dev' environment.
'''
args = [util.which('dcos')]
env = _env_reporting()
env['DCOS_PRODUCTION'] = 'false'
with patch('sys.argv', args), patch.dict(os.environ, env):
assert main() == 0
_, kwargs = requests.post.call_args_list[0]
assert kwargs['auth'].username == SEGMENT_IO_WRITE_KEY_DEV
rollbar.init.assert_called_with(ROLLBAR_SERVER_POST_KEY, 'dev')
@_mock
def test_config_set():
'''Tests that a `dcos config set core.email <email>` makes a
segment.io identify call'''
args = [util.which('dcos'), 'config', 'set', 'core.email', 'test@mail.com']
env = _env_reporting()
with patch('sys.argv', args), patch.dict(os.environ, env):
assert config_main() == 0
# segment.io
assert mock_called_some_args(requests.post,
'{}/identify'.format(SEGMENT_URL),
json={'userId': 'test@mail.com'},
timeout=1)
def _env_reporting():
path = os.path.join('tests', 'data', 'analytics', 'dcos_reporting.toml')
return {constants.DCOS_CONFIG_ENV: path}

View File

@@ -12,20 +12,24 @@ from .common import assert_command, exec_command
@pytest.fixture
def env():
return {
r = os.environ.copy()
r.update({
constants.PATH_ENV: os.environ[constants.PATH_ENV],
constants.DCOS_CONFIG_ENV: os.path.join("tests", "data", "dcos.toml"),
cli_constants.DCOS_PRODUCTION_ENV: 'false'
}
})
return r
@pytest.fixture
def missing_env():
return {
r = os.environ.copy()
r.update({
constants.PATH_ENV: os.environ[constants.PATH_ENV],
constants.DCOS_CONFIG_ENV:
os.path.join("tests", "data", "missing_params_dcos.toml")
}
})
return r
def test_help():

View File

@@ -71,9 +71,11 @@ def test_version():
def test_missing_dcos_config():
env = {
env = os.environ.copy()
del env['DCOS_CONFIG']
env.update({
constants.PATH_ENV: os.environ[constants.PATH_ENV],
}
})
stdout = (b"Environment variable 'DCOS_CONFIG' must be set "
b"to the DCOS config file.\n")
@@ -85,10 +87,11 @@ def test_missing_dcos_config():
def test_dcos_config_not_a_file():
env = {
env = os.environ.copy()
env.update({
constants.PATH_ENV: os.environ[constants.PATH_ENV],
'DCOS_CONFIG': 'missing/file',
}
})
stdout = (b"Environment variable 'DCOS_CONFIG' maps to "
b"'missing/file' and it is not a file.\n")

View File

@@ -134,11 +134,13 @@ def test_about():
@pytest.fixture
def missing_env():
return {
env = os.environ.copy()
env.update({
constants.PATH_ENV: os.environ[constants.PATH_ENV],
constants.DCOS_CONFIG_ENV:
os.path.join("tests", "data", "missing_marathon_params.toml")
}
})
return env
def test_missing_config(missing_env):

41
cli/tox.win.ini Normal file
View File

@@ -0,0 +1,41 @@
[tox]
envlist = py{27,34}-unit, py{27,34}-integration
[testenv]
setenv =
DCOS_CONFIG = {env:DCOS_CONFIG}
EXHIBITOR_URL = {env:EXHIBITOR_URL}
deps =
teamcity-messages
pytest
pytest-cov
mock
pypiwin32
-e..
[testenv:syntax]
deps =
teamcity-messages
flake8
isort
..
commands =
flake8 --verbose {env:CI_FLAGS:} dcoscli tests setup.py
isort --recursive --check-only --diff --verbose dcoscli tests setup.py
[testenv:py27-integration]
commands =
py.test -vv {env:CI_FLAGS:} tests/integrations{posargs}
[testenv:py34-integration]
commands =
py.test -vv {env:CI_FLAGS:} tests/integrations{posargs}
[testenv:py27-unit]
commands =
py.test -vv {env:CI_FLAGS:} tests/unit{posargs}
[testenv:py34-unit]
commands =
py.test -vv {env:CI_FLAGS:} tests/unit{posargs}

5
cli/win_bin/clean.ps1 Normal file
View File

@@ -0,0 +1,5 @@
$BaseDir = (Get-Location).Path
Remove-Item $BASEDIR\env -Recurse -Force -erroraction 'silentlycontinue'
Remove-Item $BASEDIR\dist -Recurse -Force -erroraction 'silentlycontinue'
Remove-Item $BASEDIR\build -Recurse -Force -erroraction 'silentlycontinue'
Get-ChildItem -Path $BaseDir -Filter *.pyc -Recurse | Remove-Item -Force

22
cli/win_bin/env.ps1 Normal file
View File

@@ -0,0 +1,22 @@
$BaseDir = (Get-Location).Path
if (-Not (Test-Path $BaseDir\env -PathType Container)) {
virtualenv -q $BASEDIR/env --prompt='(dcoscli) '
echo "Virtualenv created."
& $BASEDIR/env/Scripts/activate
echo "Virtualenv activated."
& $BASEDIR/env/Scripts/pip.exe install -r $BASEDIR/requirements.txt
& $BASEDIR/env/Scripts/pip.exe install -e $BASEDIR
echo "Requirements installed."
}
ElseIf ((Test-Path $BASEDIR/env/bin/activate )) {
& $BASEDIR/env/Scripts/activate
echo "Virtualenv activated."
& $BASEDIR/env/Scripts/pip install -r $BASEDIR/requirements.txt
& $BASEDIR/env/Scripts/pip install -e $BASEDIR
echo "Requirements installed."
}

7
cli/win_bin/packages.ps1 Normal file
View File

@@ -0,0 +1,7 @@
$BaseDir = (Get-Location).Path
echo "Building wheel..."
"$BASEDIR/env/bin/python" setup.py bdist_wheel
echo "Building egg..."
"$BASEDIR/env/bin/python" setup.py sdist

8
cli/win_bin/test.ps1 Normal file
View File

@@ -0,0 +1,8 @@
$BaseDir = (Get-Location).Path
cd $BASEDIR
& $BASEDIR\env\Scripts\activate
echo "Virtualenv activated."
tox -c tox.win.ini
exit $LastExitCode

View File

@@ -708,7 +708,9 @@ def update_sources(config, validate=False):
target_dir = os.path.join(cache_dir, source.hash())
try:
if os.path.exists(target_dir):
shutil.rmtree(target_dir, ignore_errors=False)
shutil.rmtree(target_dir,
onerror=_rmtree_on_error,
ignore_errors=False)
except OSError:
err = Error(
'Could not remove directory [{}]'.format(target_dir))
@@ -926,7 +928,8 @@ PATH = {}""".format(os.environ[constants.PATH_ENV]))
branch='master')
# Remove .git directory to save space.
shutil.rmtree(os.path.join(target_dir, ".git"))
shutil.rmtree(os.path.join(target_dir, ".git"),
onerror=_rmtree_on_error)
return None
except git.exc.GitCommandError:
@@ -934,6 +937,30 @@ PATH = {}""".format(os.environ[constants.PATH_ENV]))
'Unable to fetch packages from [{}]'.format(self.url))
def _rmtree_on_error(func, path, exc_info):
"""Error handler for ``shutil.rmtree``.
If the error is due to an access error (read only file)
it attempts to add write permission and then retries.
If the error is for another reason it re-raises the error.
Usage : ``shutil.rmtree(path, onerror=onerror)``.
:param func: Function which raised the exception.
:type func: function
:param path: The path name passed to ``shutil.rmtree`` function.
:type path: str
:param exc_info: Information about the last raised exception.
:type exc_info: tuple
:rtype: None
"""
import stat
if not os.access(path, os.W_OK):
os.chmod(path, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
func(path)
else:
raise
class Error(errors.Error):
"""Class for describing errors during packaging operations.
@@ -976,8 +1003,16 @@ class Registry():
# TODO(CD): implement these checks in pure Python?
scripts_dir = os.path.join(self._base_path, 'scripts')
validate_script = os.path.join(scripts_dir, '1-validate-packages.sh')
result = subprocess.call(validate_script)
if util.is_windows_platform():
validate_script = os.path.join(scripts_dir,
'1-validate-packages.ps1')
cmd = ['powershell', '-ExecutionPolicy',
'ByPass', '-File', validate_script]
result = subprocess.call(cmd)
else:
validate_script = os.path.join(scripts_dir,
'1-validate-packages.sh')
result = subprocess.call(validate_script)
if result is not 0:
return [Error(
'Source tree is not valid [{}]'.format(self._base_path))]

View File

@@ -158,7 +158,8 @@ def which(program):
exe_file = os.path.join(path, program)
if is_exe(exe_file):
return exe_file
if is_windows_platform() and not program.endswith('.exe'):
return which(program + '.exe')
return None
@@ -169,8 +170,7 @@ def dcos_path():
:rtype: str
"""
dcos_bin_dir = os.path.realpath(sys.argv[0])
return os.path.dirname(os.path.dirname(dcos_bin_dir))
return os.path.dirname(os.path.dirname(os.sys.executable))
def configure_logger_from_environ():

30
tox.win.ini Normal file
View File

@@ -0,0 +1,30 @@
[tox]
envlist = py{27,34}-unit
[testenv]
setenv =
DCOS_CONFIG = {env:DCOS_CONFIG}
EXHIBITOR_URL = {env:EXHIBITOR_URL}
deps =
teamcity-messages
pytest
pytest-cov
pypiwin32
[testenv:syntax]
deps =
teamcity-messages
flake8
isort
commands =
flake8 --verbose {env:CI_FLAGS:} dcos tests setup.py
isort --recursive --check-only --diff --verbose dcos tests setup.py
[testenv:py27-unit]
commands =
py.test -vv {env:CI_FLAGS:} --cov {envsitepackagesdir}/dcos tests
[testenv:py34-unit]
commands =
py.test -vv {env:CI_FLAGS:} --cov {envsitepackagesdir}/dcos tests

5
win_bin/clean.ps1 Normal file
View File

@@ -0,0 +1,5 @@
$BaseDir = (Get-Location).Path
Remove-Item $BASEDIR\env -Recurse -Force -erroraction 'silentlycontinue'
Remove-Item $BASEDIR\dist -Recurse -Force -erroraction 'silentlycontinue'
Remove-Item $BASEDIR\build -Recurse -Force -erroraction 'silentlycontinue'
Get-ChildItem -Path $BaseDir -Filter *.pyc -Recurse | Remove-Item -Force

22
win_bin/env.ps1 Normal file
View File

@@ -0,0 +1,22 @@
$BaseDir = (Get-Location).Path
if (-Not (Test-Path $BaseDir\env -PathType Container)) {
virtualenv -q $BASEDIR/env --prompt='(dcoscli) '
echo "Virtualenv created."
& $BASEDIR/env/Scripts/activate
echo "Virtualenv activated."
& $BASEDIR/env/Scripts/pip.exe install -r $BASEDIR/requirements.txt
& $BASEDIR/env/Scripts/pip.exe install -e $BASEDIR
echo "Requirements installed."
}
ElseIf ((Test-Path $BASEDIR/env/bin/activate )) {
& $BASEDIR/env/Scripts/activate
echo "Virtualenv activated."
& $BASEDIR/env/Scripts/pip install -r $BASEDIR/requirements.txt
& $BASEDIR/env/Scripts/pip install -e $BASEDIR
echo "Requirements installed."
}

7
win_bin/packages.ps1 Normal file
View File

@@ -0,0 +1,7 @@
$BaseDir = (Get-Location).Path
echo "Building wheel..."
& "$BASEDIR\env\Scripts\python.exe" setup.py bdist_wheel
echo "Building egg..."
& "$BASEDIR\env\Scripts\python.exe" setup.py sdist

16
win_bin/start_tests.ps1 Normal file
View File

@@ -0,0 +1,16 @@
$BaseDir = (Get-Location).Path
& $BaseDir\win_bin\clean.ps1
& $BaseDir\win_bin\env.ps1
& $BaseDir\win_bin\packages.ps1
& $BaseDir\env\Scripts\activate
tox -c tox.win.ini
$DcosCliExitCode = $LastExitCode
& $BaseDir\env\Scripts\deactivate
cd cli
& $BaseDir\cli\win_bin\clean.ps1
& $BaseDir\cli\win_bin\env.ps1
& $BaseDir\cli\env\Scripts\activate
tox -c tox.win.ini
$CliExitCode = $LastExitCode
& $BaseDir\cli\env\Scripts\deactivate
exit ($DcosCliExitCode -or $CliExitCode)

7
win_bin/test.ps1 Normal file
View File

@@ -0,0 +1,7 @@
$BaseDir = (Get-Location).Path
cd $BASEDIR
& $BASEDIR\env\Scripts\activate
echo "Virtualenv activated."
tox