Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a test against infinite prompt during cluster setup #1031

Merged
merged 4 commits into from
Aug 23, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion cli/dcoscli/node/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ def _bundle_download(bundle, location):
msg = ('Diagnostics bundle size is {}, '
'are you sure you want to download it?')
if not confirm(msg.format(sizeof_fmt(bundle_size)), False):
return 0
return 1

r = _do_request(url, 'GET', stream=True)
try:
Expand Down
2 changes: 1 addition & 1 deletion cli/dcoscli/package/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ def _install(package_name, package_version, options_path, app_id, cli,

if not confirm('Continue installing?', yes):
emitter.publish('Exiting installation.')
return 0
return 1

if app and pkg.marathon_template():

Expand Down
20 changes: 17 additions & 3 deletions cli/tests/integrations/helpers/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from dcos import config, http


def exec_command(cmd, env=None, stdin=None):
def exec_command(cmd, env=None, stdin=None, timeout=None):
"""Execute CLI command

:param cmd: Program and arguments
Expand All @@ -21,6 +21,10 @@ def exec_command(cmd, env=None, stdin=None):
:type env: dict | None
:param stdin: File to use for stdin
:type stdin: file
:param timeout: If the process doesn't terminate after this timeout,
it will get killed and a subprocess.TimeoutExpired
exception will be raised. The timeout is in seconds.
:type timeout: int
:returns: A tuple with the returncode, stdout and stderr
:rtype: (int, bytes, bytes)
"""
Expand All @@ -34,9 +38,19 @@ def exec_command(cmd, env=None, stdin=None):
stderr=subprocess.PIPE,
env=env)

try:
streams = process.communicate(timeout=timeout)
except subprocess.TimeoutExpired:
# The child process is not killed if the timeout expires, so in order
# to cleanup properly a well-behaved application should kill the child
# process and finish communication.
# https://docs.python.org/3.5/library/subprocess.html#subprocess.Popen.communicate
process.kill()
process.communicate()
raise

# 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()]
stdout, stderr = [stream.replace(b'\r', b'') for stream in streams]

# We should always print the stdout and stderr
print('STDOUT: {}'.format(_truncate(stdout.decode('utf-8'))))
Expand Down
22 changes: 22 additions & 0 deletions cli/tests/integrations/test_cluster.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import json
import subprocess

from .helpers.common import assert_command, exec_command

Expand Down Expand Up @@ -43,3 +44,24 @@ def test_rename():

# rename back to original name
assert_command(['dcos', 'cluster', 'rename', new_name, name])


def test_setup_noninteractive():
"""
Run "dcos cluster setup" command as non-interactive with a 30 sec timeout.
This makes sure the process doesn't prompt for input forever (DCOS-15590).
"""

try:
returncode, stdout, _ = exec_command(
['dcos',
'cluster',
'setup',
'https://dcos.snakeoil.mesosphere.com'],
timeout=30,
stdin=subprocess.DEVNULL)
except subprocess.TimeoutExpired:
assert False, 'timed out waiting for process to exit'

assert returncode == 1
assert b"'' is not a valid response" in stdout
17 changes: 16 additions & 1 deletion cli/tests/integrations/test_package.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import contextlib
import json
import os
import subprocess
import sys

import pytest
Expand Down Expand Up @@ -416,6 +417,19 @@ def test_install_bad_package_version():
stderr=stderr)


def test_install_noninteractive():
try:
returncode, stdout, _ = exec_command(
['dcos', 'package', 'install', 'hello-world'],
timeout=30,
stdin=subprocess.DEVNULL)
except subprocess.TimeoutExpired:
assert False, 'timed out waiting for process to exit'

assert returncode == 1
assert b"'' is not a valid response" in stdout


def test_package_metadata():
_install_helloworld()

Expand Down Expand Up @@ -683,7 +697,8 @@ def test_install_no():
b'catalog-terms-conditions/#community-services\n'
b'A sample pre-installation message\n'
b'Continue installing? [yes/no] Exiting installation.\n'
)
),
returncode=1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. At first I thought this seemed strange to return a 1 if the user supplied no as valid input. The reason being that the command exits cleanly, whether the user inputs yes or no (the only difference being whether the package was actually installed or not). I would have expected a 1 only if there was some internal error that made the command exit prematurely.

On thinking about it a bit more though, I agree with the semantics you have in place. Use a 0 to indicate that the command successfully carried out what you asked it to; use a 1 to indicate that it didn't.

An example demonstrating these semantics in a standard unix environment:

$ ls
foo        bar        baz
$ ls | grep foo
$ echo $?
0
$ ls | grep qux
$ echo $?
1

)


Expand Down