diff --git a/tests/test_arguments.py b/tests/test_arguments.py index 32b2590..dbaa200 100644 --- a/tests/test_arguments.py +++ b/tests/test_arguments.py @@ -18,20 +18,10 @@ from wakatime.constants import ( SUCCESS, ) from wakatime.utils import get_user_agent -from wakatime.packages.requests.models import Response -from . import utils - -try: - from .packages import simplejson as json -except (ImportError, SyntaxError): - import json -try: - from mock import ANY -except ImportError: - from unittest.mock import ANY +from .utils import mock, json, ANY, CustomResponse, TemporaryDirectory, TestCase -class ArgumentsTestCase(utils.TestCase): +class ArgumentsTestCase(TestCase): patch_these = [ 'wakatime.packages.requests.adapters.HTTPAdapter.send', 'wakatime.offlinequeue.Queue.push', @@ -43,7 +33,9 @@ class ArgumentsTestCase(utils.TestCase): ['wakatime.session_cache.SessionCache.connect', None], ] - def test_help_contents(self): + @log_capture() + def test_help_contents(self, logs): + logging.disable(logging.NOTSET) args = ['--help'] with self.assertRaises(SystemExit) as e: execute(args) @@ -52,16 +44,17 @@ class ArgumentsTestCase(utils.TestCase): expected_stdout = open('tests/samples/output/test_help_contents').read() self.assertEquals(sys.stdout.getvalue(), expected_stdout) self.assertEquals(sys.stderr.getvalue(), '') + self.assertNothingLogged(logs) self.patched['wakatime.offlinequeue.Queue.push'].assert_not_called() self.patched['wakatime.offlinequeue.Queue.pop'].assert_not_called() - def test_argument_parsing(self): - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + @log_capture() + def test_argument_parsing(self, logs): + logging.disable(logging.NOTSET) + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() - with utils.TemporaryDirectory() as tempdir: + with TemporaryDirectory() as tempdir: entity = 'tests/samples/codefiles/twolinefile.txt' shutil.copy(entity, os.path.join(tempdir, 'twolinefile.txt')) entity = os.path.realpath(os.path.join(tempdir, 'twolinefile.txt')) @@ -72,8 +65,8 @@ class ArgumentsTestCase(utils.TestCase): retval = execute(args) self.assertEquals(retval, SUCCESS) - self.assertEquals(sys.stdout.getvalue(), '') - self.assertEquals(sys.stderr.getvalue(), '') + self.assertNothingPrinted() + self.assertNothingLogged(logs) self.patched['wakatime.session_cache.SessionCache.get'].assert_called_once_with() self.patched['wakatime.session_cache.SessionCache.delete'].assert_not_called() @@ -86,9 +79,7 @@ class ArgumentsTestCase(utils.TestCase): def test_argument_parsing_strips_quotes(self, logs): logging.disable(logging.NOTSET) - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() now = u(int(time.time())) config = 'tests/samples/configs/good_config.cfg' @@ -125,10 +116,7 @@ class ArgumentsTestCase(utils.TestCase): @log_capture() def test_lineno_and_cursorpos(self, logs): logging.disable(logging.NOTSET) - - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() entity = 'tests/samples/codefiles/twolinefile.txt' config = 'tests/samples/configs/good_config.cfg' @@ -162,12 +150,12 @@ class ArgumentsTestCase(utils.TestCase): self.assertOfflineHeartbeatsSynced() self.assertSessionCacheSaved() - def test_invalid_timeout_passed_via_command_line(self): - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + @log_capture() + def test_invalid_timeout_passed_via_command_line(self, logs): + logging.disable(logging.NOTSET) + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() - with utils.TemporaryDirectory() as tempdir: + with TemporaryDirectory() as tempdir: entity = 'tests/samples/codefiles/twolinefile.txt' shutil.copy(entity, os.path.join(tempdir, 'twolinefile.txt')) entity = os.path.realpath(os.path.join(tempdir, 'twolinefile.txt')) @@ -178,6 +166,7 @@ class ArgumentsTestCase(utils.TestCase): with self.assertRaises(SystemExit) as e: execute(args) + self.assertNothingLogged(logs) self.assertEquals(int(str(e.exception)), 2) self.assertEquals(sys.stdout.getvalue(), '') expected_stderr = open('tests/samples/output/main_test_timeout_passed_via_command_line').read() @@ -191,9 +180,7 @@ class ArgumentsTestCase(utils.TestCase): def test_missing_entity_file(self, logs): logging.disable(logging.NOTSET) - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() entity = 'tests/samples/codefiles/missingfile.txt' @@ -216,9 +203,7 @@ class ArgumentsTestCase(utils.TestCase): def test_missing_entity_argument(self, logs): logging.disable(logging.NOTSET) - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() config = 'tests/samples/configs/good_config.cfg' args = ['--config', config] @@ -246,9 +231,7 @@ class ArgumentsTestCase(utils.TestCase): def test_missing_api_key(self, logs): logging.disable(logging.NOTSET) - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() config = 'tests/samples/configs/missing_api_key.cfg' args = ['--config', config] @@ -276,9 +259,7 @@ class ArgumentsTestCase(utils.TestCase): def test_invalid_api_key(self, logs): logging.disable(logging.NOTSET) - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() key = 'an-invalid-key' args = ['--key', key] @@ -306,11 +287,9 @@ class ArgumentsTestCase(utils.TestCase): def test_api_key_passed_via_command_line(self, logs): logging.disable(logging.NOTSET) - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() - with utils.TemporaryDirectory() as tempdir: + with TemporaryDirectory() as tempdir: filename = list(filter(lambda x: x.endswith('.txt'), os.listdir(u('tests/samples/codefiles/unicode'))))[0] entity = os.path.join('tests/samples/codefiles/unicode', filename) shutil.copy(entity, os.path.join(tempdir, filename)) @@ -344,12 +323,12 @@ class ArgumentsTestCase(utils.TestCase): self.assertOfflineHeartbeatsSynced() self.assertSessionCacheSaved() - def test_proxy_argument(self): - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + @log_capture() + def test_proxy_argument(self, logs): + logging.disable(logging.NOTSET) + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() - with utils.TemporaryDirectory() as tempdir: + with TemporaryDirectory() as tempdir: entity = 'tests/samples/codefiles/emptyfile.txt' shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt')) entity = os.path.realpath(os.path.join(tempdir, 'emptyfile.txt')) @@ -359,8 +338,8 @@ class ArgumentsTestCase(utils.TestCase): args = ['--file', entity, '--config', config, '--proxy', proxy] retval = execute(args) self.assertEquals(retval, SUCCESS) - self.assertEquals(sys.stdout.getvalue(), '') - self.assertEquals(sys.stderr.getvalue(), '') + self.assertNothingPrinted() + self.assertNothingLogged(logs) self.patched['wakatime.session_cache.SessionCache.get'].assert_called_once_with() self.patched['wakatime.session_cache.SessionCache.delete'].assert_not_called() @@ -371,12 +350,12 @@ class ArgumentsTestCase(utils.TestCase): self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].assert_called_once_with(ANY, cert=None, proxies={'https': proxy}, stream=False, timeout=60, verify=True) - def test_disable_ssl_verify_argument(self): - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + @log_capture() + def test_disable_ssl_verify_argument(self, logs): + logging.disable(logging.NOTSET) + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() - with utils.TemporaryDirectory() as tempdir: + with TemporaryDirectory() as tempdir: entity = 'tests/samples/codefiles/emptyfile.txt' shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt')) entity = os.path.realpath(os.path.join(tempdir, 'emptyfile.txt')) @@ -385,8 +364,8 @@ class ArgumentsTestCase(utils.TestCase): args = ['--file', entity, '--config', config, '--no-ssl-verify'] retval = execute(args) self.assertEquals(retval, SUCCESS) - self.assertEquals(sys.stdout.getvalue(), '') - self.assertEquals(sys.stderr.getvalue(), '') + self.assertNothingPrinted() + self.assertNothingLogged(logs) self.patched['wakatime.session_cache.SessionCache.get'].assert_called_once_with() self.patched['wakatime.session_cache.SessionCache.delete'].assert_not_called() @@ -401,11 +380,9 @@ class ArgumentsTestCase(utils.TestCase): def test_write_argument(self, logs): logging.disable(logging.NOTSET) - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() - with utils.TemporaryDirectory() as tempdir: + with TemporaryDirectory() as tempdir: entity = 'tests/samples/codefiles/emptyfile.txt' shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt')) entity = os.path.realpath(os.path.join(tempdir, 'emptyfile.txt')) @@ -442,9 +419,7 @@ class ArgumentsTestCase(utils.TestCase): def test_entity_type_domain(self, logs): logging.disable(logging.NOTSET) - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() entity = 'google.com' config = 'tests/samples/configs/good_config.cfg' @@ -479,9 +454,7 @@ class ArgumentsTestCase(utils.TestCase): def test_entity_type_app(self, logs): logging.disable(logging.NOTSET) - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() entity = 'Firefox' config = 'tests/samples/configs/good_config.cfg' @@ -516,9 +489,7 @@ class ArgumentsTestCase(utils.TestCase): def test_old_alternate_language_argument_still_supported(self, logs): logging.disable(logging.NOTSET) - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() language = 'Java' now = u(int(time.time())) @@ -555,8 +526,8 @@ class ArgumentsTestCase(utils.TestCase): def test_extra_heartbeats_alternate_project_not_used(self, logs): logging.disable(logging.NOTSET) - response = Response() - response.status_code = 201 + response = CustomResponse() + response.response_text = '[[{"id":1},201], [{"id":1},201]]' self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response now1 = u(int(time.time())) @@ -567,7 +538,7 @@ class ArgumentsTestCase(utils.TestCase): config = 'tests/samples/configs/good_config.cfg' args = ['--time', now1, '--file', entity1, '--config', config, '--extra-heartbeats'] - with utils.mock.patch('wakatime.main.sys.stdin') as mock_stdin: + with mock.patch('wakatime.main.sys.stdin') as mock_stdin: now2 = int(time.time()) heartbeats = json.dumps([{ 'timestamp': now2, @@ -618,8 +589,8 @@ class ArgumentsTestCase(utils.TestCase): def test_extra_heartbeats_using_project_from_editor(self, logs): logging.disable(logging.NOTSET) - response = Response() - response.status_code = 201 + response = CustomResponse() + response.response_text = '[[{"id":1},201], [{"id":1},201]]' self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response now1 = u(int(time.time())) @@ -630,7 +601,7 @@ class ArgumentsTestCase(utils.TestCase): config = 'tests/samples/configs/good_config.cfg' args = ['--time', now1, '--file', entity1, '--config', config, '--extra-heartbeats'] - with utils.mock.patch('wakatime.main.sys.stdin') as mock_stdin: + with mock.patch('wakatime.main.sys.stdin') as mock_stdin: now2 = int(time.time()) heartbeats = json.dumps([{ 'timestamp': now2, @@ -681,11 +652,11 @@ class ArgumentsTestCase(utils.TestCase): def test_extra_heartbeats_when_project_not_detected(self, logs): logging.disable(logging.NOTSET) - response = Response() - response.status_code = 201 + response = CustomResponse() + response.response_text = '[[{"id":1},201], [{"id":1},201]]' self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response - with utils.TemporaryDirectory() as tempdir: + with TemporaryDirectory() as tempdir: entity = 'tests/samples/codefiles/twolinefile.txt' shutil.copy(entity, os.path.join(tempdir, 'twolinefile.txt')) @@ -696,7 +667,7 @@ class ArgumentsTestCase(utils.TestCase): config = 'tests/samples/configs/good_config.cfg' args = ['--time', now1, '--file', entity1, '--config', config, '--extra-heartbeats'] - with utils.mock.patch('wakatime.main.sys.stdin') as mock_stdin: + with mock.patch('wakatime.main.sys.stdin') as mock_stdin: now2 = int(time.time()) heartbeats = json.dumps([{ 'timestamp': now2, @@ -745,11 +716,11 @@ class ArgumentsTestCase(utils.TestCase): def test_extra_heartbeats_when_project_not_detected_alternate_project_used(self, logs): logging.disable(logging.NOTSET) - response = Response() - response.status_code = 201 + response = CustomResponse() + response.response_text = '[[{"id":1},201], [{"id":1},201]]' self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response - with utils.TemporaryDirectory() as tempdir: + with TemporaryDirectory() as tempdir: entity = 'tests/samples/codefiles/twolinefile.txt' shutil.copy(entity, os.path.join(tempdir, 'twolinefile.txt')) @@ -761,7 +732,7 @@ class ArgumentsTestCase(utils.TestCase): config = 'tests/samples/configs/good_config.cfg' args = ['--time', now1, '--file', entity1, '--config', config, '--extra-heartbeats'] - with utils.mock.patch('wakatime.main.sys.stdin') as mock_stdin: + with mock.patch('wakatime.main.sys.stdin') as mock_stdin: now2 = int(time.time()) heartbeats = json.dumps([{ 'timestamp': now2, @@ -811,11 +782,9 @@ class ArgumentsTestCase(utils.TestCase): def test_extra_heartbeats_with_malformed_json(self, logs): logging.disable(logging.NOTSET) - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() - with utils.TemporaryDirectory() as tempdir: + with TemporaryDirectory() as tempdir: entity = 'tests/samples/codefiles/twolinefile.txt' shutil.copy(entity, os.path.join(tempdir, 'twolinefile.txt')) entity = os.path.realpath(os.path.join(tempdir, 'twolinefile.txt')) @@ -824,7 +793,7 @@ class ArgumentsTestCase(utils.TestCase): config = 'tests/samples/configs/good_config.cfg' args = ['--file', entity, '--config', config, '--extra-heartbeats'] - with utils.mock.patch('wakatime.main.sys.stdin') as mock_stdin: + with mock.patch('wakatime.main.sys.stdin') as mock_stdin: heartbeats = '[{foobar}]' mock_stdin.readline.return_value = heartbeats @@ -840,8 +809,10 @@ class ArgumentsTestCase(utils.TestCase): self.assertOfflineHeartbeatsSynced() self.assertSessionCacheSaved() - def test_uses_wakatime_home_env_variable(self): - with utils.TemporaryDirectory() as tempdir: + @log_capture() + def test_uses_wakatime_home_env_variable(self, logs): + logging.disable(logging.NOTSET) + with TemporaryDirectory() as tempdir: entity = 'tests/samples/codefiles/twolinefile.txt' shutil.copy(entity, os.path.join(tempdir, 'twolinefile.txt')) entity = os.path.realpath(os.path.join(tempdir, 'twolinefile.txt')) @@ -851,12 +822,14 @@ class ArgumentsTestCase(utils.TestCase): args = ['--file', entity, '--key', key, '--config', config] - with utils.mock.patch.object(sys, 'argv', ['wakatime'] + args): + with mock.patch.object(sys, 'argv', ['wakatime'] + args): args, configs = parse_arguments() self.assertEquals(args.logfile, None) - with utils.mock.patch('os.environ.get') as mock_env: + with mock.patch('os.environ.get') as mock_env: mock_env.return_value = os.path.realpath(tempdir) args, configs = parse_arguments() self.assertEquals(args.logfile, logfile) + self.assertNothingPrinted() + self.assertNothingLogged(logs) diff --git a/tests/test_configs.py b/tests/test_configs.py index f0fb8d9..7cf6709 100644 --- a/tests/test_configs.py +++ b/tests/test_configs.py @@ -20,11 +20,10 @@ from wakatime.constants import ( SUCCESS, ) from wakatime.packages.requests.models import Response -from . import utils -from .utils import ANY +from .utils import mock, ANY, CustomResponse, TemporaryDirectory, TestCase -class ConfigsTestCase(utils.TestCase): +class ConfigsTestCase(TestCase): patch_these = [ 'wakatime.packages.requests.adapters.HTTPAdapter.send', 'wakatime.offlinequeue.Queue.push', @@ -37,20 +36,18 @@ class ConfigsTestCase(utils.TestCase): ] def test_config_file_not_passed_in_command_line_args(self): - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() - with utils.TemporaryDirectory() as tempdir: + with TemporaryDirectory() as tempdir: entity = 'tests/samples/codefiles/emptyfile.txt' shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt')) entity = os.path.realpath(os.path.join(tempdir, 'emptyfile.txt')) args = ['--file', entity, '--logfile', '~/.wakatime.log'] - with utils.mock.patch('wakatime.configs.os.environ.get') as mock_env: + with mock.patch('wakatime.configs.os.environ.get') as mock_env: mock_env.return_value = None - with utils.mock.patch('wakatime.configs.open') as mock_open: + with mock.patch('wakatime.configs.open') as mock_open: mock_open.side_effect = IOError('') with self.assertRaises(SystemExit) as e: @@ -67,11 +64,9 @@ class ConfigsTestCase(utils.TestCase): def test_config_file_from_env(self, logs): logging.disable(logging.NOTSET) - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() - with utils.TemporaryDirectory() as tempdir: + with TemporaryDirectory() as tempdir: entity = 'tests/samples/codefiles/emptyfile.txt' shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt')) entity = os.path.realpath(os.path.join(tempdir, 'emptyfile.txt')) @@ -79,7 +74,7 @@ class ConfigsTestCase(utils.TestCase): shutil.copy(config, os.path.join(tempdir, '.wakatime.cfg')) config = os.path.realpath(os.path.join(tempdir, '.wakatime.cfg')) - with utils.mock.patch('wakatime.configs.os.environ.get') as mock_env: + with mock.patch('wakatime.configs.os.environ.get') as mock_env: mock_env.return_value = tempdir args = ['--file', entity, '--logfile', '~/.wakatime.log'] @@ -100,7 +95,7 @@ class ConfigsTestCase(utils.TestCase): def test_missing_config_file(self): config = 'foo' - with utils.TemporaryDirectory() as tempdir: + with TemporaryDirectory() as tempdir: entity = 'tests/samples/codefiles/emptyfile.txt' shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt')) entity = os.path.realpath(os.path.join(tempdir, 'emptyfile.txt')) @@ -119,11 +114,9 @@ class ConfigsTestCase(utils.TestCase): self.patched['wakatime.session_cache.SessionCache.get'].assert_not_called() def test_good_config_file(self): - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() - with utils.TemporaryDirectory() as tempdir: + with TemporaryDirectory() as tempdir: entity = 'tests/samples/codefiles/emptyfile.txt' shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt')) entity = os.path.realpath(os.path.join(tempdir, 'emptyfile.txt')) @@ -150,11 +143,9 @@ class ConfigsTestCase(utils.TestCase): apikey = XXX """ - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() - with utils.TemporaryDirectory() as tempdir: + with TemporaryDirectory() as tempdir: entity = 'tests/samples/codefiles/emptyfile.txt' shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt')) entity = os.path.realpath(os.path.join(tempdir, 'emptyfile.txt')) @@ -177,7 +168,7 @@ class ConfigsTestCase(utils.TestCase): def test_bad_config_file(self, logs): logging.disable(logging.NOTSET) - with utils.TemporaryDirectory() as tempdir: + with TemporaryDirectory() as tempdir: entity = 'tests/samples/codefiles/emptyfile.txt' shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt')) entity = os.path.realpath(os.path.join(tempdir, 'emptyfile.txt')) @@ -206,11 +197,9 @@ class ConfigsTestCase(utils.TestCase): def test_non_hidden_filename(self, logs): logging.disable(logging.NOTSET) - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() - with utils.TemporaryDirectory() as tempdir: + with TemporaryDirectory() as tempdir: entity = 'tests/samples/codefiles/twolinefile.txt' shutil.copy(entity, os.path.join(tempdir, 'twolinefile.txt')) entity = os.path.realpath(os.path.join(tempdir, 'twolinefile.txt')) @@ -246,11 +235,9 @@ class ConfigsTestCase(utils.TestCase): self.assertSessionCacheSaved() def test_hide_all_filenames(self): - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() - with utils.TemporaryDirectory() as tempdir: + with TemporaryDirectory() as tempdir: entity = 'tests/samples/codefiles/python.py' shutil.copy(entity, os.path.join(tempdir, 'python.py')) entity = os.path.realpath(os.path.join(tempdir, 'python.py')) @@ -283,11 +270,9 @@ class ConfigsTestCase(utils.TestCase): self.assertSessionCacheSaved() def test_hide_all_filenames_from_cli_arg(self): - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() - with utils.TemporaryDirectory() as tempdir: + with TemporaryDirectory() as tempdir: entity = 'tests/samples/codefiles/python.py' shutil.copy(entity, os.path.join(tempdir, 'python.py')) entity = os.path.realpath(os.path.join(tempdir, 'python.py')) @@ -320,11 +305,9 @@ class ConfigsTestCase(utils.TestCase): self.assertSessionCacheSaved() def test_hide_matching_filenames(self): - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() - with utils.TemporaryDirectory() as tempdir: + with TemporaryDirectory() as tempdir: entity = 'tests/samples/codefiles/python.py' shutil.copy(entity, os.path.join(tempdir, 'python.py')) entity = os.path.realpath(os.path.join(tempdir, 'python.py')) @@ -360,11 +343,9 @@ class ConfigsTestCase(utils.TestCase): self.assertSessionCacheSaved() def test_does_not_hide_unmatching_filenames(self): - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() - with utils.TemporaryDirectory() as tempdir: + with TemporaryDirectory() as tempdir: entity = 'tests/samples/codefiles/python.py' shutil.copy(entity, os.path.join(tempdir, 'python.py')) entity = os.path.realpath(os.path.join(tempdir, 'python.py')) @@ -401,11 +382,9 @@ class ConfigsTestCase(utils.TestCase): def test_does_not_hide_filenames_from_invalid_regex(self, logs): logging.disable(logging.NOTSET) - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() - with utils.TemporaryDirectory() as tempdir: + with TemporaryDirectory() as tempdir: entity = 'tests/samples/codefiles/emptyfile.txt' shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt')) entity = os.path.realpath(os.path.join(tempdir, 'emptyfile.txt')) @@ -453,7 +432,7 @@ class ConfigsTestCase(utils.TestCase): response.status_code = 0 self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response - with utils.TemporaryDirectory() as tempdir: + with TemporaryDirectory() as tempdir: entity = 'tests/samples/codefiles/emptyfile.txt' shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt')) entity = os.path.realpath(os.path.join(tempdir, 'emptyfile.txt')) @@ -474,11 +453,9 @@ class ConfigsTestCase(utils.TestCase): self.assertSessionCacheUntouched() def test_hostname_set_from_config_file(self): - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() - with utils.TemporaryDirectory() as tempdir: + with TemporaryDirectory() as tempdir: entity = 'tests/samples/codefiles/emptyfile.txt' shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt')) entity = os.path.realpath(os.path.join(tempdir, 'emptyfile.txt')) @@ -500,11 +477,9 @@ class ConfigsTestCase(utils.TestCase): self.assertSessionCacheSaved() def test_no_ssl_verify_from_config_file(self): - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() - with utils.TemporaryDirectory() as tempdir: + with TemporaryDirectory() as tempdir: entity = 'tests/samples/codefiles/emptyfile.txt' shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt')) entity = os.path.realpath(os.path.join(tempdir, 'emptyfile.txt')) diff --git a/tests/test_dependencies.py b/tests/test_dependencies.py index a86cc43..86d6c10 100644 --- a/tests/test_dependencies.py +++ b/tests/test_dependencies.py @@ -14,13 +14,11 @@ from wakatime.constants import SUCCESS from wakatime.exceptions import NotYetImplemented from wakatime.dependencies import DependencyParser, TokenParser from wakatime.packages.pygments.lexers import ClassNotFound, PythonLexer -from wakatime.packages.requests.models import Response from wakatime.stats import get_lexer_by_name -from . import utils -from .utils import ANY +from .utils import mock, ANY, CustomResponse, TemporaryDirectory, TestCase -class DependenciesTestCase(utils.TestCase): +class DependenciesTestCase(TestCase): patch_these = [ 'wakatime.packages.requests.adapters.HTTPAdapter.send', 'wakatime.offlinequeue.Queue.push', @@ -33,13 +31,11 @@ class DependenciesTestCase(utils.TestCase): ] def shared(self, expected_dependencies=[], expected_language=ANY, expected_lines=ANY, entity='', config='good_config.cfg', extra_args=[]): - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() config = os.path.join('tests/samples/configs', config) - with utils.TemporaryDirectory() as tempdir: + with TemporaryDirectory() as tempdir: shutil.copy(os.path.join('tests/samples/codefiles', entity), os.path.join(tempdir, os.path.basename(entity))) entity = os.path.realpath(os.path.join(tempdir, os.path.basename(entity))) @@ -74,7 +70,7 @@ class DependenciesTestCase(utils.TestCase): parser = TokenParser(source_file) parser.parse() - with utils.mock.patch('wakatime.dependencies.TokenParser._extract_tokens') as mock_extract_tokens: + with mock.patch('wakatime.dependencies.TokenParser._extract_tokens') as mock_extract_tokens: source_file = 'tests/samples/codefiles/see.h' parser = TokenParser(source_file) parser.tokens @@ -144,7 +140,7 @@ class DependenciesTestCase(utils.TestCase): log = logging.getLogger('WakaTime') log.setLevel(logging.DEBUG) - with utils.mock.patch('wakatime.dependencies.import_module') as mock_import: + with mock.patch('wakatime.dependencies.import_module') as mock_import: mock_import.side_effect = ImportError('foo') lexer = PythonLexer @@ -164,7 +160,7 @@ class DependenciesTestCase(utils.TestCase): self.assertEquals(dependencies, expected) def test_io_error_suppressed_when_parsing_dependencies(self): - with utils.mock.patch('wakatime.dependencies.open') as mock_open: + with mock.patch('wakatime.dependencies.open') as mock_open: mock_open.side_effect = IOError('') self.shared( @@ -179,10 +175,10 @@ class DependenciesTestCase(utils.TestCase): get_lexer_by_name(None) def test_classnotfound_error_suppressed_when_parsing_dependencies(self): - with utils.mock.patch('wakatime.stats.guess_lexer_using_filename') as mock_guess: + with mock.patch('wakatime.stats.guess_lexer_using_filename') as mock_guess: mock_guess.return_value = (None, None) - with utils.mock.patch('wakatime.stats.get_filetype_from_buffer') as mock_filetype: + with mock.patch('wakatime.stats.get_filetype_from_buffer') as mock_filetype: mock_filetype.return_value = 'foo' self.shared( @@ -338,7 +334,7 @@ class DependenciesTestCase(utils.TestCase): ) def test_dependencies_still_detected_when_alternate_language_used(self): - with utils.mock.patch('wakatime.stats.smart_guess_lexer') as mock_guess_lexer: + with mock.patch('wakatime.stats.smart_guess_lexer') as mock_guess_lexer: mock_guess_lexer.return_value = None self.shared( diff --git a/tests/test_languages.py b/tests/test_languages.py index adc2715..8c867d8 100644 --- a/tests/test_languages.py +++ b/tests/test_languages.py @@ -8,10 +8,9 @@ import os import time from wakatime.compat import u from wakatime.constants import SUCCESS -from wakatime.packages.requests.models import Response from wakatime.stats import guess_language from . import utils -from .utils import ANY +from .utils import ANY, CustomResponse class LanguagesTestCase(utils.TestCase): @@ -27,9 +26,7 @@ class LanguagesTestCase(utils.TestCase): ] def shared(self, expected_language='', entity='', extra_args=[]): - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() config = 'tests/samples/configs/good_config.cfg' entity = os.path.join('tests/samples/codefiles', entity) diff --git a/tests/test_main.py b/tests/test_main.py index d3a3cfd..090db11 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -22,7 +22,7 @@ from wakatime.packages import tzlocal from wakatime.packages.requests.exceptions import RequestException from wakatime.packages.requests.models import Response from . import utils -from .utils import ANY +from .utils import ANY, CustomResponse class MainTestCase(utils.TestCase): @@ -266,9 +266,7 @@ class MainTestCase(utils.TestCase): def test_invalid_api_key(self, logs): logging.disable(logging.NOTSET) - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() config = 'tests/samples/configs/missing_api_key.cfg' args = ['--config', config, '--key', 'invalid-api-key'] @@ -291,9 +289,7 @@ class MainTestCase(utils.TestCase): self.assertSessionCacheUntouched() def test_nonascii_hostname(self): - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() with utils.TemporaryDirectory() as tempdir: entity = 'tests/samples/codefiles/emptyfile.txt' @@ -320,9 +316,7 @@ class MainTestCase(utils.TestCase): self.assertSessionCacheSaved() def test_nonascii_timezone(self): - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() with utils.TemporaryDirectory() as tempdir: entity = 'tests/samples/codefiles/emptyfile.txt' @@ -354,9 +348,7 @@ class MainTestCase(utils.TestCase): self.assertSessionCacheSaved() def test_timezone_with_invalid_encoding(self): - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() with utils.TemporaryDirectory() as tempdir: entity = 'tests/samples/codefiles/emptyfile.txt' @@ -391,9 +383,7 @@ class MainTestCase(utils.TestCase): self.assertSessionCacheSaved() def test_tzlocal_exception(self): - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() with utils.TemporaryDirectory() as tempdir: entity = 'tests/samples/codefiles/emptyfile.txt' @@ -419,9 +409,7 @@ class MainTestCase(utils.TestCase): self.assertSessionCacheSaved() def test_timezone_header(self): - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() with utils.TemporaryDirectory() as tempdir: entity = 'tests/samples/codefiles/emptyfile.txt' @@ -447,9 +435,7 @@ class MainTestCase(utils.TestCase): def test_nonascii_filename(self, logs): logging.disable(logging.NOTSET) - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() with utils.TemporaryDirectory() as tempdir: filename = list(filter(lambda x: x.endswith('.txt'), os.listdir(u('tests/samples/codefiles/unicode'))))[0] diff --git a/tests/test_offlinequeue.py b/tests/test_offlinequeue.py index 9ab5003..0b7b3f5 100644 --- a/tests/test_offlinequeue.py +++ b/tests/test_offlinequeue.py @@ -13,10 +13,10 @@ import time import uuid from testfixtures import log_capture from wakatime.compat import u -from wakatime.constants import SUCCESS +from wakatime.constants import API_ERROR, AUTH_ERROR, SUCCESS from wakatime.packages.requests.models import Response from . import utils -from .utils import ANY, json +from .utils import ANY, json, CustomResponse class OfflineQueueTestCase(utils.TestCase): @@ -84,7 +84,9 @@ class OfflineQueueTestCase(utils.TestCase): args = ['--file', entity, '--config', config, '--time', now] execute(args) - response.status_code = 201 + response = CustomResponse() + response.response_text = '[[{"id":1},201], [{"id":1},201], [{"id":1},201]]' + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response execute(args) queue = Queue(None, None) @@ -121,7 +123,10 @@ class OfflineQueueTestCase(utils.TestCase): entity3 = 'tests/samples/codefiles/python.py' project3 = 'proj3' args = ['--file', entity3, '--config', config, '--time', now3, '--project', project3] - response.status_code = 201 + + response = CustomResponse() + response.response_text = '[[{"id":1},201], [{"id":1},201], [{"id":1},201]]' + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response execute(args) # offline queue should be empty @@ -184,21 +189,9 @@ class OfflineQueueTestCase(utils.TestCase): key = str(uuid.uuid4()) args = ['--file', os.path.join(tempdir, entities[0]), '--key', key, '--config', 'tests/samples/configs/good_config.cfg', '--time', now, '--extra-heartbeats'] - class CustomResponse(Response): - - @property - def status_code(self): - return 202 - - @status_code.setter - def status_code(self, value): - pass - - @property - def text(self): - return '[[{"id":1},201], [{"error":"error 2"},500], [{"id":3},201], [{"error":4},500]]' - response = CustomResponse() + response.response_code = 202 + response.response_text = '[[{"id":1},201], [{"error":"error 2"},500], [{"id":3},201], [{"error":4},500]]' self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response with utils.mock.patch('wakatime.main.sys.stdin') as mock_stdin: @@ -279,21 +272,64 @@ class OfflineQueueTestCase(utils.TestCase): key = str(uuid.uuid4()) args = ['--file', os.path.join(tempdir, entities[0]), '--key', key, '--config', 'tests/samples/configs/good_config.cfg', '--time', now, '--extra-heartbeats'] - class CustomResponse(Response): + response = CustomResponse() + response.response_code = 202 + response.response_text = '[[{"id":1},201], [{"error":"error 2"},500], [{"id":3},201], [{"error":4},500]]' + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response - @property - def status_code(self): - return 202 + with utils.mock.patch('wakatime.main.sys.stdin') as mock_stdin: + heartbeats = json.dumps([{ + 'timestamp': now, + 'entity': os.path.join(tempdir, entity), + 'entity_type': 'file', + 'is_write': False, + } for entity in entities[1:]]) + mock_stdin.readline.return_value = heartbeats - @status_code.setter - def status_code(self, value): - pass + retval = execute(args) + self.assertEquals(retval, SUCCESS) + self.assertNothingPrinted() - @property - def text(self): - return '[[{"id":1},201], [{"error":"error 2"},500], [{"id":3},201], [{"error":4},500]]' + expected = 'WakaTime WARNING Results from api not matching heartbeats sent.' + actual = self.getLogOutput(logs) + self.assertEquals(actual, expected) + + queue = Queue(None, None) + self.assertEquals(queue._get_db_file(), fh.name) + saved_heartbeats = queue.pop_many() + self.assertNothingPrinted() + + # make sure all offline heartbeats were sent, so queue should only have 1 heartbeat left from the second 500 response + self.assertEquals(len(saved_heartbeats), 1) + + @log_capture() + def test_leftover_heartbeats_saved_when_bulk_response_not_matching_length(self, logs): + logging.disable(logging.NOTSET) + + with utils.NamedTemporaryFile() as fh: + with utils.mock.patch('wakatime.offlinequeue.Queue._get_db_file') as mock_db_file: + mock_db_file.return_value = fh.name + + entities = [ + 'emptyfile.txt', + 'twolinefile.txt', + 'python.py', + 'go.go', + 'java.java', + 'php.php', + ] + + with utils.TemporaryDirectory() as tempdir: + for entity in entities: + shutil.copy(os.path.join('tests/samples/codefiles', entity), os.path.join(tempdir, entity)) + + now = u(int(time.time())) + key = str(uuid.uuid4()) + args = ['--file', os.path.join(tempdir, entities[0]), '--key', key, '--config', 'tests/samples/configs/good_config.cfg', '--time', now, '--extra-heartbeats'] response = CustomResponse() + response.response_code = 202 + response.response_text = '[[{"id":1},201], [{"id":3},201]]' self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response with utils.mock.patch('wakatime.main.sys.stdin') as mock_stdin: @@ -313,10 +349,13 @@ class OfflineQueueTestCase(utils.TestCase): self.assertEquals(queue._get_db_file(), fh.name) saved_heartbeats = queue.pop_many() self.assertNothingPrinted() - self.assertNothingLogged(logs) - # make sure all offline heartbeats were sent, so queue should only have 1 heartbeat left from the second 500 response - self.assertEquals(len(saved_heartbeats), 1) + expected = "WakaTime WARNING Missing 4 results from api.\nWakaTime WARNING Missing 2 results from api." + actual = self.getLogOutput(logs) + self.assertEquals(actual, expected) + + # make sure extra heartbeats not matching server response were saved + self.assertEquals(len(saved_heartbeats), 2) def test_auth_error_when_sending_offline_heartbeats(self): with utils.NamedTemporaryFile() as fh: @@ -349,30 +388,20 @@ class OfflineQueueTestCase(utils.TestCase): project3 = 'proj3' args = ['--file', entity3, '--config', config, '--time', now3, '--project', project3] - class CustomResponse(Response): - count = 0 - - @property - def status_code(self): - if self.count > 2: - return 401 - self.count += 1 - return 201 - - @status_code.setter - def status_code(self, value): - pass response = CustomResponse() + response.second_response_code = 401 + response.limit = 2 + response.response_text = '[[{"id":1},201], [{"id":1},201], [{"id":1},201]]' self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response retval = execute(args) - self.assertEquals(retval, SUCCESS) + self.assertEquals(retval, AUTH_ERROR) - # offline queue should be empty + # offline queue should still have saved heartbeats queue = Queue(None, None) - saved_heartbeat = queue.pop() + saved_heartbeats = queue.pop_many() self.assertNothingPrinted() - self.assertIsNone(saved_heartbeat) + self.assertEquals(len(saved_heartbeats), 2) def test_500_error_when_sending_offline_heartbeats(self): with utils.NamedTemporaryFile() as fh: @@ -405,30 +434,20 @@ class OfflineQueueTestCase(utils.TestCase): project3 = 'proj3' args = ['--file', entity3, '--config', config, '--time', now3, '--project', project3] - class CustomResponse(Response): - count = 0 - - @property - def status_code(self): - if self.count > 2: - return 500 - self.count += 1 - return 201 - - @status_code.setter - def status_code(self, value): - pass response = CustomResponse() + response.second_response_code = 500 + response.limit = 2 + response.response_text = '[[{"id":1},201], [{"id":1},201], [{"id":1},201]]' self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response retval = execute(args) - self.assertEquals(retval, SUCCESS) + self.assertEquals(retval, API_ERROR) - # offline queue should be empty + # offline queue should still have saved heartbeats queue = Queue(None, None) - saved_heartbeat = queue.pop() + saved_heartbeats = queue.pop_many() self.assertNothingPrinted() - self.assertIsNone(saved_heartbeat) + self.assertEquals(len(saved_heartbeats), 2) def test_empty_project_can_be_saved(self): with utils.NamedTemporaryFile() as fh: diff --git a/tests/test_project.py b/tests/test_project.py index 2af195e..7599df6 100644 --- a/tests/test_project.py +++ b/tests/test_project.py @@ -18,7 +18,7 @@ from wakatime.constants import API_ERROR, SUCCESS from wakatime.exceptions import NotYetImplemented from wakatime.projects.base import BaseProject from . import utils -from .utils import ANY, json +from .utils import ANY, CustomResponse, json class ProjectTestCase(utils.TestCase): @@ -34,9 +34,7 @@ class ProjectTestCase(utils.TestCase): ] def shared(self, expected_project='', expected_branch=ANY, entity='', config='good_config.cfg', extra_args=[]): - response = Response() - response.status_code = 201 - self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response + self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse() config = os.path.join('tests/samples/configs', config) if not os.path.exists(entity): diff --git a/tests/test_proxy.py b/tests/test_proxy.py index 1b03d8a..26c162b 100644 --- a/tests/test_proxy.py +++ b/tests/test_proxy.py @@ -11,9 +11,10 @@ import sys from testfixtures import log_capture from wakatime.compat import u from wakatime.constants import API_ERROR, SUCCESS -from wakatime.packages.requests.models import Response from wakatime.packages.requests.exceptions import RequestException +from wakatime.packages.requests.models import Response from . import utils +from .utils import CustomResponse try: from mock import ANY, call @@ -34,8 +35,7 @@ class ProxyTestCase(utils.TestCase): ] def test_proxy_without_protocol(self): - response = Response() - response.status_code = 201 + response = CustomResponse() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response with utils.TemporaryDirectory() as tempdir: @@ -61,8 +61,7 @@ class ProxyTestCase(utils.TestCase): self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].assert_called_once_with(ANY, cert=None, proxies={'https': proxy}, stream=False, timeout=60, verify=True) def test_https_proxy(self): - response = Response() - response.status_code = 201 + response = CustomResponse() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response with utils.TemporaryDirectory() as tempdir: @@ -88,8 +87,7 @@ class ProxyTestCase(utils.TestCase): self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].assert_called_once_with(ANY, cert=None, proxies={'https': proxy}, stream=False, timeout=60, verify=True) def test_socks_proxy(self): - response = Response() - response.status_code = 201 + response = CustomResponse() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response with utils.TemporaryDirectory() as tempdir: @@ -225,8 +223,7 @@ class ProxyTestCase(utils.TestCase): def test_invalid_proxy(self, logs): logging.disable(logging.NOTSET) - response = Response() - response.status_code = 201 + response = CustomResponse() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response with utils.TemporaryDirectory() as tempdir: diff --git a/tests/utils.py b/tests/utils.py index 7034262..939f586 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -6,6 +6,7 @@ import sys import tempfile from wakatime.compat import u +from wakatime.packages.requests.models import Response try: @@ -134,6 +135,9 @@ class TestCase(unittest.TestCase): self.assertEquals(sys.stdout.getvalue(), '') self.assertEquals(sys.stderr.getvalue(), '') + def getPrintedOutput(self): + return sys.stdout.getvalue() or '' + sys.stderr.getvalue() or '' + def assertNothingLogged(self, logs): self.assertEquals(self.getLogOutput(logs), '') @@ -219,3 +223,31 @@ class DynamicIterable(object): def next(self): return self.__next__() + + +class CustomResponse(Response): + response_code = 201 + response_text = '[[{"id":1},201]]' + limit = 0 + second_response_code = 0 + second_response_text = None + + _count = 0 + + @property + def status_code(self): + if self.limit and self._count > self.limit: + return self.second_response_code + self._count += 1 + return self.response_code + + @status_code.setter + def status_code(self, value): + pass + + @property + def text(self): + if self.limit and self._count > self.limit: + return self.second_response_text if self.second_response_text is not None else self.response_text + self._count += 1 + return self.response_text diff --git a/wakatime/api.py b/wakatime/api.py index 99fa0b8..7d7b1b5 100644 --- a/wakatime/api.py +++ b/wakatime/api.py @@ -161,7 +161,7 @@ def _process_server_results(heartbeats, code, content, results, args, configs): for i in range(len(results)): if len(heartbeats) <= i: - log.debug('Results from server do not match heartbeats sent.') + log.warn('Results from api not matching heartbeats sent.') break try: @@ -177,6 +177,12 @@ def _process_server_results(heartbeats, code, content, results, args, configs): if not _success(c): _handle_unsent_heartbeats([heartbeats[i]], c, text, args, configs) + leftover = len(heartbeats) - len(results) + if leftover > 0: + log.warn('Missing {0} results from api.'.format(leftover)) + start = len(heartbeats) - leftover + _handle_unsent_heartbeats(heartbeats[start:], code, content, args, configs) + def _handle_unsent_heartbeats(heartbeats, code, content, args, configs): if args.offline: