From a030c30110bf27f5f9c16a2f8f7b97c319c18691 Mon Sep 17 00:00:00 2001 From: Michael Gummelt Date: Tue, 14 Apr 2015 14:25:33 -0700 Subject: [PATCH 01/11] segment.io tracking --- cli/dcoscli/main.py | 47 +++++++++++++++++++++++-- cli/setup.py | 2 ++ cli/tests/integrations/cli/test_dcos.py | 34 ++++++++++++++++++ 3 files changed, 81 insertions(+), 2 deletions(-) diff --git a/cli/dcoscli/main.py b/cli/dcoscli/main.py index ab5d008..4ce754d 100644 --- a/cli/dcoscli/main.py +++ b/cli/dcoscli/main.py @@ -28,8 +28,11 @@ to read about a specific subcommand. import os -import subprocess +import sys +import logging +from subprocess import Popen, PIPE +import analytics import dcoscli import docopt from dcos.api import constants, emitting, subcommand, util @@ -54,6 +57,10 @@ def main(): emitter.publish(err) return 1 + # The requests package emits INFO logs. We want to exclude those, + # even if the user has selected --log-level=INFO. + logging.getLogger('requests').setLevel(logging.WARNING) + command = args[''] if not command: @@ -64,7 +71,43 @@ def main(): emitter.publish(err) return 1 - return subprocess.call([executable, command] + args['']) + subproc = Popen([executable, command] + args[''], + stderr=PIPE) + + return wait_and_track(subproc) + + + +WRITE_KEY = '51ybGTeFEFU1xo6u10XMDrr6kATFyRyh' +def wait_and_track(subproc): + # capture and print stderr + err = '' + while subproc.poll() is None: + err_buff = subproc.stderr.read() + sys.stderr.write(err_buff) + err += err_buff + + exit_code = subproc.poll() + + # segment.io analytics + analytics.write_key = WRITE_KEY + try: + # We don't have user id's right now, but segment.io requires + # them, so we use a constant (1) + analytics.track(1, 'dcos-cli', { + 'cmd': ' '.join(sys.argv), + 'exit_code': exit_code, + 'err': err or None + }) + + analytics.flush() + except: + # ignore segment.io exceptions + pass + + return exit_code + + def _config_log_level_environ(log_level): diff --git a/cli/setup.py b/cli/setup.py index ac77710..c9b8645 100644 --- a/cli/setup.py +++ b/cli/setup.py @@ -67,6 +67,8 @@ setup( 'pkginfo', 'toml', 'virtualenv', + 'analytics-python', + 'requests[security]' ], # If there are data files included in your packages that need to be diff --git a/cli/tests/integrations/cli/test_dcos.py b/cli/tests/integrations/cli/test_dcos.py index 4405269..561fd31 100644 --- a/cli/tests/integrations/cli/test_dcos.py +++ b/cli/tests/integrations/cli/test_dcos.py @@ -1,10 +1,16 @@ import os +import mock +from mock import Mock +import analytics + +from dcoscli.main import main from dcos.api import constants, util from common import exec_command + def test_default(): dcos_path = os.path.dirname(os.path.dirname(util.which('dcos'))) returncode, stdout, stderr = exec_command(['dcos']) @@ -124,3 +130,31 @@ def test_invalid_log_level_flag(): b"values are ['debug', 'info', 'warning', 'error', " b"'critical']\n") assert stderr == b'' + +def test_analytics_no_err(): + args = ['dcos'] + with mock.patch('sys.argv', args): + analytics.track = Mock() + analytics.flush = Mock() + exit_code = main() + analytics.track.assert_called_with(1, 'dcos-cli', + {'cmd': ' '.join(args), + 'exit_code': 0, + 'err': None}) + analytics.flush.assert_called_with() + + assert exit_code == 0 + +def test_analytics_err(): + args = ['dcos', 'marathon', 'task', 'show', 'asdf'] + with mock.patch('sys.argv', args): + analytics.track = Mock() + analytics.flush = Mock() + exit_code = main() + analytics.track.assert_called_with(1, 'dcos-cli', + {'cmd': ' '.join(args), + 'exit_code': 1, + 'err': "Task 'asdf' does not exist\n"}) + analytics.flush.assert_called_with() + + assert exit_code == 1 From 0a621678d09dd40cfb95a3bc0944e2196033821f Mon Sep 17 00:00:00 2001 From: Michael Gummelt Date: Tue, 14 Apr 2015 15:37:14 -0700 Subject: [PATCH 02/11] add 'mock' package as a tox.ini dependency --- cli/tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/cli/tox.ini b/cli/tox.ini index 8a952fe..119c752 100644 --- a/cli/tox.ini +++ b/cli/tox.ini @@ -5,6 +5,7 @@ envlist = py{27,34}-integration, syntax deps = pytest pytest-cov + mock -e.. [testenv:syntax] From a6833941414261daf3196bc73469241c66cc7562 Mon Sep 17 00:00:00 2001 From: Michael Gummelt Date: Tue, 14 Apr 2015 15:52:34 -0700 Subject: [PATCH 03/11] remove 'requests[security]' dependency --- cli/setup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cli/setup.py b/cli/setup.py index c9b8645..5bc8a48 100644 --- a/cli/setup.py +++ b/cli/setup.py @@ -68,7 +68,6 @@ setup( 'toml', 'virtualenv', 'analytics-python', - 'requests[security]' ], # If there are data files included in your packages that need to be From 68b5dc717800a4e259a2ab6034fa2131f609a890 Mon Sep 17 00:00:00 2001 From: Michael Gummelt Date: Tue, 14 Apr 2015 16:41:05 -0700 Subject: [PATCH 04/11] silence urllib3 ssl message --- cli/dcoscli/main.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cli/dcoscli/main.py b/cli/dcoscli/main.py index 4ce754d..9a3b16f 100644 --- a/cli/dcoscli/main.py +++ b/cli/dcoscli/main.py @@ -35,6 +35,7 @@ from subprocess import Popen, PIPE import analytics import dcoscli import docopt +import requests from dcos.api import constants, emitting, subcommand, util emitter = emitting.FlatEmitter() @@ -61,6 +62,10 @@ def main(): # even if the user has selected --log-level=INFO. logging.getLogger('requests').setLevel(logging.WARNING) + # urllib3 is printing an SSL warning we want to silence. See + # DCOS-1007. + requests.packages.urllib3.disable_warnings() + command = args[''] if not command: From 5bed47489dd5045efaf5a8071cfd2262ad9b2570 Mon Sep 17 00:00:00 2001 From: Michael Gummelt Date: Tue, 14 Apr 2015 18:08:47 -0700 Subject: [PATCH 05/11] make python3 friendly via .decode --- cli/dcoscli/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/dcoscli/main.py b/cli/dcoscli/main.py index 9a3b16f..b847314 100644 --- a/cli/dcoscli/main.py +++ b/cli/dcoscli/main.py @@ -88,7 +88,7 @@ def wait_and_track(subproc): # capture and print stderr err = '' while subproc.poll() is None: - err_buff = subproc.stderr.read() + err_buff = subproc.stderr.read().decode('utf-8') sys.stderr.write(err_buff) err += err_buff From f146238c57179faff5d1d53fe6119799f9c73310 Mon Sep 17 00:00:00 2001 From: Michael Gummelt Date: Tue, 14 Apr 2015 18:56:34 -0700 Subject: [PATCH 06/11] formatting --- cli/dcoscli/main.py | 10 ++++------ cli/tests/data/dcos.toml | 2 +- cli/tests/integrations/cli/test_dcos.py | 18 +++++++++--------- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/cli/dcoscli/main.py b/cli/dcoscli/main.py index b847314..5c3deef 100644 --- a/cli/dcoscli/main.py +++ b/cli/dcoscli/main.py @@ -27,10 +27,10 @@ to read about a specific subcommand. """ +import logging import os import sys -import logging -from subprocess import Popen, PIPE +from subprocess import PIPE, Popen import analytics import dcoscli @@ -40,6 +40,8 @@ from dcos.api import constants, emitting, subcommand, util emitter = emitting.FlatEmitter() +WRITE_KEY = '51ybGTeFEFU1xo6u10XMDrr6kATFyRyh' + def main(): if not _is_valid_configuration(): @@ -82,8 +84,6 @@ def main(): return wait_and_track(subproc) - -WRITE_KEY = '51ybGTeFEFU1xo6u10XMDrr6kATFyRyh' def wait_and_track(subproc): # capture and print stderr err = '' @@ -113,8 +113,6 @@ def wait_and_track(subproc): return exit_code - - def _config_log_level_environ(log_level): """ :param log_level: Log level to set diff --git a/cli/tests/data/dcos.toml b/cli/tests/data/dcos.toml index 4dec770..d7a000f 100644 --- a/cli/tests/data/dcos.toml +++ b/cli/tests/data/dcos.toml @@ -4,5 +4,5 @@ pip_find_links = "../dist" host = "localhost" port = 8080 [package] -sources = [ "git://github.com/mesosphere/universe.git", "https://github.com/mesosphere/universe/archive/master.zip",] +sources = [ "new_uri", "git://github.com/mesosphere/universe.git", "https://github.com/mesosphere/universe/archive/master.zip",] cache = "tmp/cache" diff --git a/cli/tests/integrations/cli/test_dcos.py b/cli/tests/integrations/cli/test_dcos.py index 561fd31..d40b576 100644 --- a/cli/tests/integrations/cli/test_dcos.py +++ b/cli/tests/integrations/cli/test_dcos.py @@ -1,14 +1,12 @@ import os -import mock -from mock import Mock import analytics - -from dcoscli.main import main from dcos.api import constants, util +from dcoscli.main import main +import mock from common import exec_command - +from mock import Mock def test_default(): @@ -131,6 +129,7 @@ def test_invalid_log_level_flag(): b"'critical']\n") assert stderr == b'' + def test_analytics_no_err(): args = ['dcos'] with mock.patch('sys.argv', args): @@ -145,16 +144,17 @@ def test_analytics_no_err(): assert exit_code == 0 + def test_analytics_err(): args = ['dcos', 'marathon', 'task', 'show', 'asdf'] with mock.patch('sys.argv', args): analytics.track = Mock() analytics.flush = Mock() exit_code = main() - analytics.track.assert_called_with(1, 'dcos-cli', - {'cmd': ' '.join(args), - 'exit_code': 1, - 'err': "Task 'asdf' does not exist\n"}) + attrs = {'cmd': ' '.join(args), + 'exit_code': 1, + 'err': "Task 'asdf' does not exist\n"} + analytics.track.assert_called_with(1, 'dcos-cli', attrs) analytics.flush.assert_called_with() assert exit_code == 1 From 9f707b88d06ab0f85deb404e81a47f2735d8b8bd Mon Sep 17 00:00:00 2001 From: Michael Gummelt Date: Wed, 15 Apr 2015 13:45:45 -0700 Subject: [PATCH 07/11] added a new test config file moved test config files to their own directories refactored tests added a test for new core.report config var --- cli/dcoscli/constants.py | 1 + cli/dcoscli/main.py | 21 +++++---- cli/tests/data/config/dcos.toml | 8 ++++ cli/tests/data/dcos.toml | 8 ---- cli/tests/data/dcos/dcos_no_reporting.toml | 2 + cli/tests/integrations/cli/test_config.py | 2 +- cli/tests/integrations/cli/test_dcos.py | 53 ++++++++++++---------- 7 files changed, 55 insertions(+), 40 deletions(-) create mode 100644 cli/tests/data/config/dcos.toml delete mode 100644 cli/tests/data/dcos.toml create mode 100644 cli/tests/data/dcos/dcos_no_reporting.toml diff --git a/cli/dcoscli/constants.py b/cli/dcoscli/constants.py index e69de29..86bcd40 100644 --- a/cli/dcoscli/constants.py +++ b/cli/dcoscli/constants.py @@ -0,0 +1 @@ +SEGMENT_IO_WRITE_KEY = '51ybGTeFEFU1xo6u10XMDrr6kATFyRyh' diff --git a/cli/dcoscli/main.py b/cli/dcoscli/main.py index 5c3deef..40dd4c7 100644 --- a/cli/dcoscli/main.py +++ b/cli/dcoscli/main.py @@ -36,11 +36,12 @@ import analytics import dcoscli import docopt import requests -from dcos.api import constants, emitting, subcommand, util +from dcos.api import constants, emitting, subcommand, util, config +from dcoscli.constants import SEGMENT_IO_WRITE_KEY emitter = emitting.FlatEmitter() -WRITE_KEY = '51ybGTeFEFU1xo6u10XMDrr6kATFyRyh' + def main(): @@ -60,10 +61,6 @@ def main(): emitter.publish(err) return 1 - # The requests package emits INFO logs. We want to exclude those, - # even if the user has selected --log-level=INFO. - logging.getLogger('requests').setLevel(logging.WARNING) - # urllib3 is printing an SSL warning we want to silence. See # DCOS-1007. requests.packages.urllib3.disable_warnings() @@ -81,6 +78,7 @@ def main(): subproc = Popen([executable, command] + args[''], stderr=PIPE) + analytics.write_key = SEGMENT_IO_WRITE_KEY return wait_and_track(subproc) @@ -94,8 +92,16 @@ def wait_and_track(subproc): exit_code = subproc.poll() + con = config.load_from_path( + os.environ[constants.DCOS_CONFIG_ENV]) + + if con.get('core.report', True): + track(exit_code, err) + + return exit_code + +def track(exit_code, err): # segment.io analytics - analytics.write_key = WRITE_KEY try: # We don't have user id's right now, but segment.io requires # them, so we use a constant (1) @@ -110,7 +116,6 @@ def wait_and_track(subproc): # ignore segment.io exceptions pass - return exit_code def _config_log_level_environ(log_level): diff --git a/cli/tests/data/config/dcos.toml b/cli/tests/data/config/dcos.toml new file mode 100644 index 0000000..4dec770 --- /dev/null +++ b/cli/tests/data/config/dcos.toml @@ -0,0 +1,8 @@ +[subcommand] +pip_find_links = "../dist" +[marathon] +host = "localhost" +port = 8080 +[package] +sources = [ "git://github.com/mesosphere/universe.git", "https://github.com/mesosphere/universe/archive/master.zip",] +cache = "tmp/cache" diff --git a/cli/tests/data/dcos.toml b/cli/tests/data/dcos.toml deleted file mode 100644 index d7a000f..0000000 --- a/cli/tests/data/dcos.toml +++ /dev/null @@ -1,8 +0,0 @@ -[subcommand] -pip_find_links = "../dist" -[marathon] -host = "localhost" -port = 8080 -[package] -sources = [ "new_uri", "git://github.com/mesosphere/universe.git", "https://github.com/mesosphere/universe/archive/master.zip",] -cache = "tmp/cache" diff --git a/cli/tests/data/dcos/dcos_no_reporting.toml b/cli/tests/data/dcos/dcos_no_reporting.toml new file mode 100644 index 0000000..c463013 --- /dev/null +++ b/cli/tests/data/dcos/dcos_no_reporting.toml @@ -0,0 +1,2 @@ +[core] +report = false diff --git a/cli/tests/integrations/cli/test_config.py b/cli/tests/integrations/cli/test_config.py index bf71457..492bf86 100644 --- a/cli/tests/integrations/cli/test_config.py +++ b/cli/tests/integrations/cli/test_config.py @@ -12,7 +12,7 @@ from common import exec_command def env(): return { constants.PATH_ENV: os.environ[constants.PATH_ENV], - constants.DCOS_CONFIG_ENV: os.path.join("tests", "data", "dcos.toml") + constants.DCOS_CONFIG_ENV: os.path.join("tests", "data", "config", "dcos.toml") } diff --git a/cli/tests/integrations/cli/test_dcos.py b/cli/tests/integrations/cli/test_dcos.py index d40b576..db17634 100644 --- a/cli/tests/integrations/cli/test_dcos.py +++ b/cli/tests/integrations/cli/test_dcos.py @@ -6,7 +6,7 @@ from dcoscli.main import main import mock from common import exec_command -from mock import Mock +from mock import Mock, patch def test_default(): @@ -107,7 +107,6 @@ def test_log_level_flag(): assert returncode == 0 assert stdout == b"Get and set DCOS command line options\n" - assert stderr == b'' def test_capital_log_level_flag(): @@ -116,7 +115,6 @@ def test_capital_log_level_flag(): assert returncode == 0 assert stdout == b"Get and set DCOS command line options\n" - assert stderr == b'' def test_invalid_log_level_flag(): @@ -129,32 +127,41 @@ def test_invalid_log_level_flag(): b"'critical']\n") assert stderr == b'' - -def test_analytics_no_err(): - args = ['dcos'] +def _mock_analytics_run(args): with mock.patch('sys.argv', args): analytics.track = Mock() analytics.flush = Mock() - exit_code = main() - analytics.track.assert_called_with(1, 'dcos-cli', - {'cmd': ' '.join(args), - 'exit_code': 0, - 'err': None}) - analytics.flush.assert_called_with() + return main() - assert exit_code == 0 + +def test_analytics_no_err(): + args = ['dcos'] + exit_code = _mock_analytics_run(args) + analytics.track.assert_called_with(1, 'dcos-cli', + {'cmd': ' '.join(args), + 'exit_code': 0, + 'err': None}) + analytics.flush.assert_called_with() + assert exit_code == 0 def test_analytics_err(): args = ['dcos', 'marathon', 'task', 'show', 'asdf'] - with mock.patch('sys.argv', args): - analytics.track = Mock() - analytics.flush = Mock() - exit_code = main() - attrs = {'cmd': ' '.join(args), - 'exit_code': 1, - 'err': "Task 'asdf' does not exist\n"} - analytics.track.assert_called_with(1, 'dcos-cli', attrs) - analytics.flush.assert_called_with() + exit_code = _mock_analytics_run(args) + attrs = {'cmd': ' '.join(args), + 'exit_code': 1, + 'err': "Task 'asdf' does not exist\n"} + analytics.track.assert_called_with(1, 'dcos-cli', attrs) + analytics.flush.assert_called_with() + assert exit_code == 1 - assert exit_code == 1 + +def test_analytics_report_config(): + args = ['dcos'] + new_env = {constants.DCOS_CONFIG_ENV: + os.path.join('tests', 'data', 'dcos', 'dcos_no_reporting.toml')} + with patch.dict(os.environ, new_env): + exit_code = _mock_analytics_run(args) + assert analytics.track.call_count == 0 + assert analytics.flush.call_count == 0 + assert exit_code == 0 From cdcf7e30d77bc92f5e0a898146bac9f50f269746 Mon Sep 17 00:00:00 2001 From: Michael Gummelt Date: Wed, 15 Apr 2015 13:52:23 -0700 Subject: [PATCH 08/11] formatting --- cli/dcoscli/main.py | 7 ++----- cli/tests/integrations/cli/test_config.py | 3 ++- cli/tests/integrations/cli/test_dcos.py | 1 + 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/cli/dcoscli/main.py b/cli/dcoscli/main.py index 40dd4c7..f539d82 100644 --- a/cli/dcoscli/main.py +++ b/cli/dcoscli/main.py @@ -27,7 +27,6 @@ to read about a specific subcommand. """ -import logging import os import sys from subprocess import PIPE, Popen @@ -36,14 +35,12 @@ import analytics import dcoscli import docopt import requests -from dcos.api import constants, emitting, subcommand, util, config +from dcos.api import config, constants, emitting, subcommand, util from dcoscli.constants import SEGMENT_IO_WRITE_KEY emitter = emitting.FlatEmitter() - - def main(): if not _is_valid_configuration(): return 1 @@ -100,6 +97,7 @@ def wait_and_track(subproc): return exit_code + def track(exit_code, err): # segment.io analytics try: @@ -117,7 +115,6 @@ def track(exit_code, err): pass - def _config_log_level_environ(log_level): """ :param log_level: Log level to set diff --git a/cli/tests/integrations/cli/test_config.py b/cli/tests/integrations/cli/test_config.py index 492bf86..029f405 100644 --- a/cli/tests/integrations/cli/test_config.py +++ b/cli/tests/integrations/cli/test_config.py @@ -10,9 +10,10 @@ from common import exec_command @pytest.fixture def env(): + config_path = os.path.join("tests", "data", "config", "dcos.toml") return { constants.PATH_ENV: os.environ[constants.PATH_ENV], - constants.DCOS_CONFIG_ENV: os.path.join("tests", "data", "config", "dcos.toml") + constants.DCOS_CONFIG_ENV: config_path } diff --git a/cli/tests/integrations/cli/test_dcos.py b/cli/tests/integrations/cli/test_dcos.py index db17634..509c701 100644 --- a/cli/tests/integrations/cli/test_dcos.py +++ b/cli/tests/integrations/cli/test_dcos.py @@ -127,6 +127,7 @@ def test_invalid_log_level_flag(): b"'critical']\n") assert stderr == b'' + def _mock_analytics_run(args): with mock.patch('sys.argv', args): analytics.track = Mock() From 5965868ceda248ac52871153e43cb8f8f9cddbcd Mon Sep 17 00:00:00 2001 From: Michael Gummelt Date: Wed, 15 Apr 2015 13:59:24 -0700 Subject: [PATCH 09/11] move dcos.toml back to orig locatoin --- cli/tests/data/{config => }/dcos.toml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename cli/tests/data/{config => }/dcos.toml (100%) diff --git a/cli/tests/data/config/dcos.toml b/cli/tests/data/dcos.toml similarity index 100% rename from cli/tests/data/config/dcos.toml rename to cli/tests/data/dcos.toml From 303ba6ff55f93f5fac909c24f417a6670a1bea83 Mon Sep 17 00:00:00 2001 From: Michael Gummelt Date: Wed, 15 Apr 2015 14:05:30 -0700 Subject: [PATCH 10/11] update test_config.py with old dcos.toml location --- cli/tests/integrations/cli/test_config.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cli/tests/integrations/cli/test_config.py b/cli/tests/integrations/cli/test_config.py index 029f405..bf71457 100644 --- a/cli/tests/integrations/cli/test_config.py +++ b/cli/tests/integrations/cli/test_config.py @@ -10,10 +10,9 @@ from common import exec_command @pytest.fixture def env(): - config_path = os.path.join("tests", "data", "config", "dcos.toml") return { constants.PATH_ENV: os.environ[constants.PATH_ENV], - constants.DCOS_CONFIG_ENV: config_path + constants.DCOS_CONFIG_ENV: os.path.join("tests", "data", "dcos.toml") } From c4173de893fb3a106b5d90d41aa40fd7311def6f Mon Sep 17 00:00:00 2001 From: Michael Gummelt Date: Wed, 15 Apr 2015 14:38:26 -0700 Subject: [PATCH 11/11] add version and config info to segment.io events --- cli/dcoscli/main.py | 16 ++++++++------ cli/tests/integrations/cli/test_dcos.py | 29 +++++++++++++++++-------- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/cli/dcoscli/main.py b/cli/dcoscli/main.py index f539d82..8b69c6f 100644 --- a/cli/dcoscli/main.py +++ b/cli/dcoscli/main.py @@ -26,7 +26,7 @@ Environment Variables: to read about a specific subcommand. """ - +import json import os import sys from subprocess import PIPE, Popen @@ -89,24 +89,26 @@ def wait_and_track(subproc): exit_code = subproc.poll() - con = config.load_from_path( + conf = config.load_from_path( os.environ[constants.DCOS_CONFIG_ENV]) - if con.get('core.report', True): - track(exit_code, err) + if conf.get('core.report', True): + track(exit_code, err, conf) return exit_code -def track(exit_code, err): +def track(exit_code, err, conf): # segment.io analytics try: # We don't have user id's right now, but segment.io requires # them, so we use a constant (1) - analytics.track(1, 'dcos-cli', { + analytics.track('', 'dcos-cli', { 'cmd': ' '.join(sys.argv), 'exit_code': exit_code, - 'err': err or None + 'err': err or None, + 'dcoscli.version': dcoscli.version, + 'config': json.dumps(list(conf.property_items())) }) analytics.flush() diff --git a/cli/tests/integrations/cli/test_dcos.py b/cli/tests/integrations/cli/test_dcos.py index 509c701..e47d078 100644 --- a/cli/tests/integrations/cli/test_dcos.py +++ b/cli/tests/integrations/cli/test_dcos.py @@ -1,7 +1,9 @@ +import json import os import analytics -from dcos.api import constants, util +import dcoscli +from dcos.api import config, constants, util from dcoscli.main import main import mock @@ -135,13 +137,21 @@ def _mock_analytics_run(args): return main() +def _analytics_base_properties(args): + conf = config.load_from_path(os.environ[constants.DCOS_CONFIG_ENV]) + return {'cmd': ' '.join(args), + 'exit_code': 0, + 'err': None, + 'dcoscli.version': dcoscli.version, + 'config': json.dumps(list(conf.property_items()))} + + def test_analytics_no_err(): args = ['dcos'] exit_code = _mock_analytics_run(args) - analytics.track.assert_called_with(1, 'dcos-cli', - {'cmd': ' '.join(args), - 'exit_code': 0, - 'err': None}) + + props = _analytics_base_properties(args) + analytics.track.assert_called_with('', 'dcos-cli', props) analytics.flush.assert_called_with() assert exit_code == 0 @@ -149,10 +159,11 @@ def test_analytics_no_err(): def test_analytics_err(): args = ['dcos', 'marathon', 'task', 'show', 'asdf'] exit_code = _mock_analytics_run(args) - attrs = {'cmd': ' '.join(args), - 'exit_code': 1, - 'err': "Task 'asdf' does not exist\n"} - analytics.track.assert_called_with(1, 'dcos-cli', attrs) + + props = _analytics_base_properties(args) + props['exit_code'] = 1 + props['err'] = "Task 'asdf' does not exist\n" + analytics.track.assert_called_with('', 'dcos-cli', props) analytics.flush.assert_called_with() assert exit_code == 1