Make sure any leftover heartbeats not accepted by API are saved

This commit is contained in:
Alan Hamlett 2017-11-22 18:34:15 -08:00
parent aa58524f66
commit 9ffb677f9d
10 changed files with 254 additions and 275 deletions

View file

@ -18,20 +18,10 @@ from wakatime.constants import (
SUCCESS, SUCCESS,
) )
from wakatime.utils import get_user_agent from wakatime.utils import get_user_agent
from wakatime.packages.requests.models import Response from .utils import mock, json, ANY, CustomResponse, TemporaryDirectory, TestCase
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
class ArgumentsTestCase(utils.TestCase): class ArgumentsTestCase(TestCase):
patch_these = [ patch_these = [
'wakatime.packages.requests.adapters.HTTPAdapter.send', 'wakatime.packages.requests.adapters.HTTPAdapter.send',
'wakatime.offlinequeue.Queue.push', 'wakatime.offlinequeue.Queue.push',
@ -43,7 +33,9 @@ class ArgumentsTestCase(utils.TestCase):
['wakatime.session_cache.SessionCache.connect', None], ['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'] args = ['--help']
with self.assertRaises(SystemExit) as e: with self.assertRaises(SystemExit) as e:
execute(args) execute(args)
@ -52,16 +44,17 @@ class ArgumentsTestCase(utils.TestCase):
expected_stdout = open('tests/samples/output/test_help_contents').read() expected_stdout = open('tests/samples/output/test_help_contents').read()
self.assertEquals(sys.stdout.getvalue(), expected_stdout) self.assertEquals(sys.stdout.getvalue(), expected_stdout)
self.assertEquals(sys.stderr.getvalue(), '') self.assertEquals(sys.stderr.getvalue(), '')
self.assertNothingLogged(logs)
self.patched['wakatime.offlinequeue.Queue.push'].assert_not_called() self.patched['wakatime.offlinequeue.Queue.push'].assert_not_called()
self.patched['wakatime.offlinequeue.Queue.pop'].assert_not_called() self.patched['wakatime.offlinequeue.Queue.pop'].assert_not_called()
def test_argument_parsing(self): @log_capture()
response = Response() def test_argument_parsing(self, logs):
response.status_code = 201 logging.disable(logging.NOTSET)
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' entity = 'tests/samples/codefiles/twolinefile.txt'
shutil.copy(entity, os.path.join(tempdir, 'twolinefile.txt')) shutil.copy(entity, os.path.join(tempdir, 'twolinefile.txt'))
entity = os.path.realpath(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) retval = execute(args)
self.assertEquals(retval, SUCCESS) self.assertEquals(retval, SUCCESS)
self.assertEquals(sys.stdout.getvalue(), '') self.assertNothingPrinted()
self.assertEquals(sys.stderr.getvalue(), '') self.assertNothingLogged(logs)
self.patched['wakatime.session_cache.SessionCache.get'].assert_called_once_with() self.patched['wakatime.session_cache.SessionCache.get'].assert_called_once_with()
self.patched['wakatime.session_cache.SessionCache.delete'].assert_not_called() 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): def test_argument_parsing_strips_quotes(self, logs):
logging.disable(logging.NOTSET) logging.disable(logging.NOTSET)
response = Response() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
response.status_code = 201
self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response
now = u(int(time.time())) now = u(int(time.time()))
config = 'tests/samples/configs/good_config.cfg' config = 'tests/samples/configs/good_config.cfg'
@ -125,10 +116,7 @@ class ArgumentsTestCase(utils.TestCase):
@log_capture() @log_capture()
def test_lineno_and_cursorpos(self, logs): def test_lineno_and_cursorpos(self, logs):
logging.disable(logging.NOTSET) logging.disable(logging.NOTSET)
self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
response = Response()
response.status_code = 201
self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response
entity = 'tests/samples/codefiles/twolinefile.txt' entity = 'tests/samples/codefiles/twolinefile.txt'
config = 'tests/samples/configs/good_config.cfg' config = 'tests/samples/configs/good_config.cfg'
@ -162,12 +150,12 @@ class ArgumentsTestCase(utils.TestCase):
self.assertOfflineHeartbeatsSynced() self.assertOfflineHeartbeatsSynced()
self.assertSessionCacheSaved() self.assertSessionCacheSaved()
def test_invalid_timeout_passed_via_command_line(self): @log_capture()
response = Response() def test_invalid_timeout_passed_via_command_line(self, logs):
response.status_code = 201 logging.disable(logging.NOTSET)
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' entity = 'tests/samples/codefiles/twolinefile.txt'
shutil.copy(entity, os.path.join(tempdir, 'twolinefile.txt')) shutil.copy(entity, os.path.join(tempdir, 'twolinefile.txt'))
entity = os.path.realpath(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: with self.assertRaises(SystemExit) as e:
execute(args) execute(args)
self.assertNothingLogged(logs)
self.assertEquals(int(str(e.exception)), 2) self.assertEquals(int(str(e.exception)), 2)
self.assertEquals(sys.stdout.getvalue(), '') self.assertEquals(sys.stdout.getvalue(), '')
expected_stderr = open('tests/samples/output/main_test_timeout_passed_via_command_line').read() 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): def test_missing_entity_file(self, logs):
logging.disable(logging.NOTSET) logging.disable(logging.NOTSET)
response = Response() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
response.status_code = 201
self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response
entity = 'tests/samples/codefiles/missingfile.txt' entity = 'tests/samples/codefiles/missingfile.txt'
@ -216,9 +203,7 @@ class ArgumentsTestCase(utils.TestCase):
def test_missing_entity_argument(self, logs): def test_missing_entity_argument(self, logs):
logging.disable(logging.NOTSET) logging.disable(logging.NOTSET)
response = Response() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
response.status_code = 201
self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response
config = 'tests/samples/configs/good_config.cfg' config = 'tests/samples/configs/good_config.cfg'
args = ['--config', config] args = ['--config', config]
@ -246,9 +231,7 @@ class ArgumentsTestCase(utils.TestCase):
def test_missing_api_key(self, logs): def test_missing_api_key(self, logs):
logging.disable(logging.NOTSET) logging.disable(logging.NOTSET)
response = Response() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
response.status_code = 201
self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response
config = 'tests/samples/configs/missing_api_key.cfg' config = 'tests/samples/configs/missing_api_key.cfg'
args = ['--config', config] args = ['--config', config]
@ -276,9 +259,7 @@ class ArgumentsTestCase(utils.TestCase):
def test_invalid_api_key(self, logs): def test_invalid_api_key(self, logs):
logging.disable(logging.NOTSET) logging.disable(logging.NOTSET)
response = Response() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
response.status_code = 201
self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response
key = 'an-invalid-key' key = 'an-invalid-key'
args = ['--key', key] args = ['--key', key]
@ -306,11 +287,9 @@ class ArgumentsTestCase(utils.TestCase):
def test_api_key_passed_via_command_line(self, logs): def test_api_key_passed_via_command_line(self, logs):
logging.disable(logging.NOTSET) logging.disable(logging.NOTSET)
response = Response() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
response.status_code = 201
self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response
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] 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) entity = os.path.join('tests/samples/codefiles/unicode', filename)
shutil.copy(entity, os.path.join(tempdir, filename)) shutil.copy(entity, os.path.join(tempdir, filename))
@ -344,12 +323,12 @@ class ArgumentsTestCase(utils.TestCase):
self.assertOfflineHeartbeatsSynced() self.assertOfflineHeartbeatsSynced()
self.assertSessionCacheSaved() self.assertSessionCacheSaved()
def test_proxy_argument(self): @log_capture()
response = Response() def test_proxy_argument(self, logs):
response.status_code = 201 logging.disable(logging.NOTSET)
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' entity = 'tests/samples/codefiles/emptyfile.txt'
shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt')) shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt'))
entity = os.path.realpath(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] args = ['--file', entity, '--config', config, '--proxy', proxy]
retval = execute(args) retval = execute(args)
self.assertEquals(retval, SUCCESS) self.assertEquals(retval, SUCCESS)
self.assertEquals(sys.stdout.getvalue(), '') self.assertNothingPrinted()
self.assertEquals(sys.stderr.getvalue(), '') self.assertNothingLogged(logs)
self.patched['wakatime.session_cache.SessionCache.get'].assert_called_once_with() self.patched['wakatime.session_cache.SessionCache.get'].assert_called_once_with()
self.patched['wakatime.session_cache.SessionCache.delete'].assert_not_called() 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) 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): @log_capture()
response = Response() def test_disable_ssl_verify_argument(self, logs):
response.status_code = 201 logging.disable(logging.NOTSET)
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' entity = 'tests/samples/codefiles/emptyfile.txt'
shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt')) shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt'))
entity = os.path.realpath(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'] args = ['--file', entity, '--config', config, '--no-ssl-verify']
retval = execute(args) retval = execute(args)
self.assertEquals(retval, SUCCESS) self.assertEquals(retval, SUCCESS)
self.assertEquals(sys.stdout.getvalue(), '') self.assertNothingPrinted()
self.assertEquals(sys.stderr.getvalue(), '') self.assertNothingLogged(logs)
self.patched['wakatime.session_cache.SessionCache.get'].assert_called_once_with() self.patched['wakatime.session_cache.SessionCache.get'].assert_called_once_with()
self.patched['wakatime.session_cache.SessionCache.delete'].assert_not_called() self.patched['wakatime.session_cache.SessionCache.delete'].assert_not_called()
@ -401,11 +380,9 @@ class ArgumentsTestCase(utils.TestCase):
def test_write_argument(self, logs): def test_write_argument(self, logs):
logging.disable(logging.NOTSET) logging.disable(logging.NOTSET)
response = Response() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
response.status_code = 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/emptyfile.txt' entity = 'tests/samples/codefiles/emptyfile.txt'
shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt')) shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt'))
entity = os.path.realpath(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): def test_entity_type_domain(self, logs):
logging.disable(logging.NOTSET) logging.disable(logging.NOTSET)
response = Response() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
response.status_code = 201
self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response
entity = 'google.com' entity = 'google.com'
config = 'tests/samples/configs/good_config.cfg' config = 'tests/samples/configs/good_config.cfg'
@ -479,9 +454,7 @@ class ArgumentsTestCase(utils.TestCase):
def test_entity_type_app(self, logs): def test_entity_type_app(self, logs):
logging.disable(logging.NOTSET) logging.disable(logging.NOTSET)
response = Response() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
response.status_code = 201
self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response
entity = 'Firefox' entity = 'Firefox'
config = 'tests/samples/configs/good_config.cfg' 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): def test_old_alternate_language_argument_still_supported(self, logs):
logging.disable(logging.NOTSET) logging.disable(logging.NOTSET)
response = Response() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
response.status_code = 201
self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response
language = 'Java' language = 'Java'
now = u(int(time.time())) now = u(int(time.time()))
@ -555,8 +526,8 @@ class ArgumentsTestCase(utils.TestCase):
def test_extra_heartbeats_alternate_project_not_used(self, logs): def test_extra_heartbeats_alternate_project_not_used(self, logs):
logging.disable(logging.NOTSET) logging.disable(logging.NOTSET)
response = Response() response = CustomResponse()
response.status_code = 201 response.response_text = '[[{"id":1},201], [{"id":1},201]]'
self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response
now1 = u(int(time.time())) now1 = u(int(time.time()))
@ -567,7 +538,7 @@ class ArgumentsTestCase(utils.TestCase):
config = 'tests/samples/configs/good_config.cfg' config = 'tests/samples/configs/good_config.cfg'
args = ['--time', now1, '--file', entity1, '--config', config, '--extra-heartbeats'] 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()) now2 = int(time.time())
heartbeats = json.dumps([{ heartbeats = json.dumps([{
'timestamp': now2, 'timestamp': now2,
@ -618,8 +589,8 @@ class ArgumentsTestCase(utils.TestCase):
def test_extra_heartbeats_using_project_from_editor(self, logs): def test_extra_heartbeats_using_project_from_editor(self, logs):
logging.disable(logging.NOTSET) logging.disable(logging.NOTSET)
response = Response() response = CustomResponse()
response.status_code = 201 response.response_text = '[[{"id":1},201], [{"id":1},201]]'
self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response
now1 = u(int(time.time())) now1 = u(int(time.time()))
@ -630,7 +601,7 @@ class ArgumentsTestCase(utils.TestCase):
config = 'tests/samples/configs/good_config.cfg' config = 'tests/samples/configs/good_config.cfg'
args = ['--time', now1, '--file', entity1, '--config', config, '--extra-heartbeats'] 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()) now2 = int(time.time())
heartbeats = json.dumps([{ heartbeats = json.dumps([{
'timestamp': now2, 'timestamp': now2,
@ -681,11 +652,11 @@ class ArgumentsTestCase(utils.TestCase):
def test_extra_heartbeats_when_project_not_detected(self, logs): def test_extra_heartbeats_when_project_not_detected(self, logs):
logging.disable(logging.NOTSET) logging.disable(logging.NOTSET)
response = Response() response = CustomResponse()
response.status_code = 201 response.response_text = '[[{"id":1},201], [{"id":1},201]]'
self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response 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' entity = 'tests/samples/codefiles/twolinefile.txt'
shutil.copy(entity, os.path.join(tempdir, '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' config = 'tests/samples/configs/good_config.cfg'
args = ['--time', now1, '--file', entity1, '--config', config, '--extra-heartbeats'] 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()) now2 = int(time.time())
heartbeats = json.dumps([{ heartbeats = json.dumps([{
'timestamp': now2, 'timestamp': now2,
@ -745,11 +716,11 @@ class ArgumentsTestCase(utils.TestCase):
def test_extra_heartbeats_when_project_not_detected_alternate_project_used(self, logs): def test_extra_heartbeats_when_project_not_detected_alternate_project_used(self, logs):
logging.disable(logging.NOTSET) logging.disable(logging.NOTSET)
response = Response() response = CustomResponse()
response.status_code = 201 response.response_text = '[[{"id":1},201], [{"id":1},201]]'
self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response 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' entity = 'tests/samples/codefiles/twolinefile.txt'
shutil.copy(entity, os.path.join(tempdir, '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' config = 'tests/samples/configs/good_config.cfg'
args = ['--time', now1, '--file', entity1, '--config', config, '--extra-heartbeats'] 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()) now2 = int(time.time())
heartbeats = json.dumps([{ heartbeats = json.dumps([{
'timestamp': now2, 'timestamp': now2,
@ -811,11 +782,9 @@ class ArgumentsTestCase(utils.TestCase):
def test_extra_heartbeats_with_malformed_json(self, logs): def test_extra_heartbeats_with_malformed_json(self, logs):
logging.disable(logging.NOTSET) logging.disable(logging.NOTSET)
response = Response() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
response.status_code = 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' entity = 'tests/samples/codefiles/twolinefile.txt'
shutil.copy(entity, os.path.join(tempdir, 'twolinefile.txt')) shutil.copy(entity, os.path.join(tempdir, 'twolinefile.txt'))
entity = os.path.realpath(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' config = 'tests/samples/configs/good_config.cfg'
args = ['--file', entity, '--config', config, '--extra-heartbeats'] 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}]' heartbeats = '[{foobar}]'
mock_stdin.readline.return_value = heartbeats mock_stdin.readline.return_value = heartbeats
@ -840,8 +809,10 @@ class ArgumentsTestCase(utils.TestCase):
self.assertOfflineHeartbeatsSynced() self.assertOfflineHeartbeatsSynced()
self.assertSessionCacheSaved() self.assertSessionCacheSaved()
def test_uses_wakatime_home_env_variable(self): @log_capture()
with utils.TemporaryDirectory() as tempdir: def test_uses_wakatime_home_env_variable(self, logs):
logging.disable(logging.NOTSET)
with TemporaryDirectory() as tempdir:
entity = 'tests/samples/codefiles/twolinefile.txt' entity = 'tests/samples/codefiles/twolinefile.txt'
shutil.copy(entity, os.path.join(tempdir, 'twolinefile.txt')) shutil.copy(entity, os.path.join(tempdir, 'twolinefile.txt'))
entity = os.path.realpath(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] 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() args, configs = parse_arguments()
self.assertEquals(args.logfile, None) 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) mock_env.return_value = os.path.realpath(tempdir)
args, configs = parse_arguments() args, configs = parse_arguments()
self.assertEquals(args.logfile, logfile) self.assertEquals(args.logfile, logfile)
self.assertNothingPrinted()
self.assertNothingLogged(logs)

View file

@ -20,11 +20,10 @@ from wakatime.constants import (
SUCCESS, SUCCESS,
) )
from wakatime.packages.requests.models import Response from wakatime.packages.requests.models import Response
from . import utils from .utils import mock, ANY, CustomResponse, TemporaryDirectory, TestCase
from .utils import ANY
class ConfigsTestCase(utils.TestCase): class ConfigsTestCase(TestCase):
patch_these = [ patch_these = [
'wakatime.packages.requests.adapters.HTTPAdapter.send', 'wakatime.packages.requests.adapters.HTTPAdapter.send',
'wakatime.offlinequeue.Queue.push', 'wakatime.offlinequeue.Queue.push',
@ -37,20 +36,18 @@ class ConfigsTestCase(utils.TestCase):
] ]
def test_config_file_not_passed_in_command_line_args(self): def test_config_file_not_passed_in_command_line_args(self):
response = Response() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
response.status_code = 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/emptyfile.txt' entity = 'tests/samples/codefiles/emptyfile.txt'
shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt')) shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt'))
entity = os.path.realpath(os.path.join(tempdir, 'emptyfile.txt')) entity = os.path.realpath(os.path.join(tempdir, 'emptyfile.txt'))
args = ['--file', entity, '--logfile', '~/.wakatime.log'] 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 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('') mock_open.side_effect = IOError('')
with self.assertRaises(SystemExit) as e: with self.assertRaises(SystemExit) as e:
@ -67,11 +64,9 @@ class ConfigsTestCase(utils.TestCase):
def test_config_file_from_env(self, logs): def test_config_file_from_env(self, logs):
logging.disable(logging.NOTSET) logging.disable(logging.NOTSET)
response = Response() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
response.status_code = 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/emptyfile.txt' entity = 'tests/samples/codefiles/emptyfile.txt'
shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt')) shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt'))
entity = os.path.realpath(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')) shutil.copy(config, os.path.join(tempdir, '.wakatime.cfg'))
config = os.path.realpath(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 mock_env.return_value = tempdir
args = ['--file', entity, '--logfile', '~/.wakatime.log'] args = ['--file', entity, '--logfile', '~/.wakatime.log']
@ -100,7 +95,7 @@ class ConfigsTestCase(utils.TestCase):
def test_missing_config_file(self): def test_missing_config_file(self):
config = 'foo' config = 'foo'
with utils.TemporaryDirectory() as tempdir: with TemporaryDirectory() as tempdir:
entity = 'tests/samples/codefiles/emptyfile.txt' entity = 'tests/samples/codefiles/emptyfile.txt'
shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt')) shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt'))
entity = os.path.realpath(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() self.patched['wakatime.session_cache.SessionCache.get'].assert_not_called()
def test_good_config_file(self): def test_good_config_file(self):
response = Response() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
response.status_code = 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/emptyfile.txt' entity = 'tests/samples/codefiles/emptyfile.txt'
shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt')) shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt'))
entity = os.path.realpath(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 apikey = XXX
""" """
response = Response() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
response.status_code = 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/emptyfile.txt' entity = 'tests/samples/codefiles/emptyfile.txt'
shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt')) shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt'))
entity = os.path.realpath(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): def test_bad_config_file(self, logs):
logging.disable(logging.NOTSET) logging.disable(logging.NOTSET)
with utils.TemporaryDirectory() as tempdir: with TemporaryDirectory() as tempdir:
entity = 'tests/samples/codefiles/emptyfile.txt' entity = 'tests/samples/codefiles/emptyfile.txt'
shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt')) shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt'))
entity = os.path.realpath(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): def test_non_hidden_filename(self, logs):
logging.disable(logging.NOTSET) logging.disable(logging.NOTSET)
response = Response() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
response.status_code = 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' entity = 'tests/samples/codefiles/twolinefile.txt'
shutil.copy(entity, os.path.join(tempdir, 'twolinefile.txt')) shutil.copy(entity, os.path.join(tempdir, 'twolinefile.txt'))
entity = os.path.realpath(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() self.assertSessionCacheSaved()
def test_hide_all_filenames(self): def test_hide_all_filenames(self):
response = Response() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
response.status_code = 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/python.py' entity = 'tests/samples/codefiles/python.py'
shutil.copy(entity, os.path.join(tempdir, 'python.py')) shutil.copy(entity, os.path.join(tempdir, 'python.py'))
entity = os.path.realpath(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() self.assertSessionCacheSaved()
def test_hide_all_filenames_from_cli_arg(self): def test_hide_all_filenames_from_cli_arg(self):
response = Response() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
response.status_code = 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/python.py' entity = 'tests/samples/codefiles/python.py'
shutil.copy(entity, os.path.join(tempdir, 'python.py')) shutil.copy(entity, os.path.join(tempdir, 'python.py'))
entity = os.path.realpath(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() self.assertSessionCacheSaved()
def test_hide_matching_filenames(self): def test_hide_matching_filenames(self):
response = Response() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
response.status_code = 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/python.py' entity = 'tests/samples/codefiles/python.py'
shutil.copy(entity, os.path.join(tempdir, 'python.py')) shutil.copy(entity, os.path.join(tempdir, 'python.py'))
entity = os.path.realpath(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() self.assertSessionCacheSaved()
def test_does_not_hide_unmatching_filenames(self): def test_does_not_hide_unmatching_filenames(self):
response = Response() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
response.status_code = 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/python.py' entity = 'tests/samples/codefiles/python.py'
shutil.copy(entity, os.path.join(tempdir, 'python.py')) shutil.copy(entity, os.path.join(tempdir, 'python.py'))
entity = os.path.realpath(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): def test_does_not_hide_filenames_from_invalid_regex(self, logs):
logging.disable(logging.NOTSET) logging.disable(logging.NOTSET)
response = Response() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
response.status_code = 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/emptyfile.txt' entity = 'tests/samples/codefiles/emptyfile.txt'
shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt')) shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt'))
entity = os.path.realpath(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 response.status_code = 0
self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response 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' entity = 'tests/samples/codefiles/emptyfile.txt'
shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt')) shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt'))
entity = os.path.realpath(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() self.assertSessionCacheUntouched()
def test_hostname_set_from_config_file(self): def test_hostname_set_from_config_file(self):
response = Response() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
response.status_code = 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/emptyfile.txt' entity = 'tests/samples/codefiles/emptyfile.txt'
shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt')) shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt'))
entity = os.path.realpath(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() self.assertSessionCacheSaved()
def test_no_ssl_verify_from_config_file(self): def test_no_ssl_verify_from_config_file(self):
response = Response() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
response.status_code = 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/emptyfile.txt' entity = 'tests/samples/codefiles/emptyfile.txt'
shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt')) shutil.copy(entity, os.path.join(tempdir, 'emptyfile.txt'))
entity = os.path.realpath(os.path.join(tempdir, 'emptyfile.txt')) entity = os.path.realpath(os.path.join(tempdir, 'emptyfile.txt'))

View file

@ -14,13 +14,11 @@ from wakatime.constants import SUCCESS
from wakatime.exceptions import NotYetImplemented from wakatime.exceptions import NotYetImplemented
from wakatime.dependencies import DependencyParser, TokenParser from wakatime.dependencies import DependencyParser, TokenParser
from wakatime.packages.pygments.lexers import ClassNotFound, PythonLexer from wakatime.packages.pygments.lexers import ClassNotFound, PythonLexer
from wakatime.packages.requests.models import Response
from wakatime.stats import get_lexer_by_name from wakatime.stats import get_lexer_by_name
from . import utils from .utils import mock, ANY, CustomResponse, TemporaryDirectory, TestCase
from .utils import ANY
class DependenciesTestCase(utils.TestCase): class DependenciesTestCase(TestCase):
patch_these = [ patch_these = [
'wakatime.packages.requests.adapters.HTTPAdapter.send', 'wakatime.packages.requests.adapters.HTTPAdapter.send',
'wakatime.offlinequeue.Queue.push', '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=[]): def shared(self, expected_dependencies=[], expected_language=ANY, expected_lines=ANY, entity='', config='good_config.cfg', extra_args=[]):
response = Response() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
response.status_code = 201
self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response
config = os.path.join('tests/samples/configs', config) 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))) 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))) 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 = TokenParser(source_file)
parser.parse() 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' source_file = 'tests/samples/codefiles/see.h'
parser = TokenParser(source_file) parser = TokenParser(source_file)
parser.tokens parser.tokens
@ -144,7 +140,7 @@ class DependenciesTestCase(utils.TestCase):
log = logging.getLogger('WakaTime') log = logging.getLogger('WakaTime')
log.setLevel(logging.DEBUG) 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') mock_import.side_effect = ImportError('foo')
lexer = PythonLexer lexer = PythonLexer
@ -164,7 +160,7 @@ class DependenciesTestCase(utils.TestCase):
self.assertEquals(dependencies, expected) self.assertEquals(dependencies, expected)
def test_io_error_suppressed_when_parsing_dependencies(self): 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('') mock_open.side_effect = IOError('')
self.shared( self.shared(
@ -179,10 +175,10 @@ class DependenciesTestCase(utils.TestCase):
get_lexer_by_name(None) get_lexer_by_name(None)
def test_classnotfound_error_suppressed_when_parsing_dependencies(self): 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) 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' mock_filetype.return_value = 'foo'
self.shared( self.shared(
@ -338,7 +334,7 @@ class DependenciesTestCase(utils.TestCase):
) )
def test_dependencies_still_detected_when_alternate_language_used(self): 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 mock_guess_lexer.return_value = None
self.shared( self.shared(

View file

@ -8,10 +8,9 @@ import os
import time import time
from wakatime.compat import u from wakatime.compat import u
from wakatime.constants import SUCCESS from wakatime.constants import SUCCESS
from wakatime.packages.requests.models import Response
from wakatime.stats import guess_language from wakatime.stats import guess_language
from . import utils from . import utils
from .utils import ANY from .utils import ANY, CustomResponse
class LanguagesTestCase(utils.TestCase): class LanguagesTestCase(utils.TestCase):
@ -27,9 +26,7 @@ class LanguagesTestCase(utils.TestCase):
] ]
def shared(self, expected_language='', entity='', extra_args=[]): def shared(self, expected_language='', entity='', extra_args=[]):
response = Response() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
response.status_code = 201
self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response
config = 'tests/samples/configs/good_config.cfg' config = 'tests/samples/configs/good_config.cfg'
entity = os.path.join('tests/samples/codefiles', entity) entity = os.path.join('tests/samples/codefiles', entity)

View file

@ -22,7 +22,7 @@ from wakatime.packages import tzlocal
from wakatime.packages.requests.exceptions import RequestException from wakatime.packages.requests.exceptions import RequestException
from wakatime.packages.requests.models import Response from wakatime.packages.requests.models import Response
from . import utils from . import utils
from .utils import ANY from .utils import ANY, CustomResponse
class MainTestCase(utils.TestCase): class MainTestCase(utils.TestCase):
@ -266,9 +266,7 @@ class MainTestCase(utils.TestCase):
def test_invalid_api_key(self, logs): def test_invalid_api_key(self, logs):
logging.disable(logging.NOTSET) logging.disable(logging.NOTSET)
response = Response() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
response.status_code = 201
self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response
config = 'tests/samples/configs/missing_api_key.cfg' config = 'tests/samples/configs/missing_api_key.cfg'
args = ['--config', config, '--key', 'invalid-api-key'] args = ['--config', config, '--key', 'invalid-api-key']
@ -291,9 +289,7 @@ class MainTestCase(utils.TestCase):
self.assertSessionCacheUntouched() self.assertSessionCacheUntouched()
def test_nonascii_hostname(self): def test_nonascii_hostname(self):
response = Response() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
response.status_code = 201
self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response
with utils.TemporaryDirectory() as tempdir: with utils.TemporaryDirectory() as tempdir:
entity = 'tests/samples/codefiles/emptyfile.txt' entity = 'tests/samples/codefiles/emptyfile.txt'
@ -320,9 +316,7 @@ class MainTestCase(utils.TestCase):
self.assertSessionCacheSaved() self.assertSessionCacheSaved()
def test_nonascii_timezone(self): def test_nonascii_timezone(self):
response = Response() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
response.status_code = 201
self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response
with utils.TemporaryDirectory() as tempdir: with utils.TemporaryDirectory() as tempdir:
entity = 'tests/samples/codefiles/emptyfile.txt' entity = 'tests/samples/codefiles/emptyfile.txt'
@ -354,9 +348,7 @@ class MainTestCase(utils.TestCase):
self.assertSessionCacheSaved() self.assertSessionCacheSaved()
def test_timezone_with_invalid_encoding(self): def test_timezone_with_invalid_encoding(self):
response = Response() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
response.status_code = 201
self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response
with utils.TemporaryDirectory() as tempdir: with utils.TemporaryDirectory() as tempdir:
entity = 'tests/samples/codefiles/emptyfile.txt' entity = 'tests/samples/codefiles/emptyfile.txt'
@ -391,9 +383,7 @@ class MainTestCase(utils.TestCase):
self.assertSessionCacheSaved() self.assertSessionCacheSaved()
def test_tzlocal_exception(self): def test_tzlocal_exception(self):
response = Response() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
response.status_code = 201
self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response
with utils.TemporaryDirectory() as tempdir: with utils.TemporaryDirectory() as tempdir:
entity = 'tests/samples/codefiles/emptyfile.txt' entity = 'tests/samples/codefiles/emptyfile.txt'
@ -419,9 +409,7 @@ class MainTestCase(utils.TestCase):
self.assertSessionCacheSaved() self.assertSessionCacheSaved()
def test_timezone_header(self): def test_timezone_header(self):
response = Response() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
response.status_code = 201
self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response
with utils.TemporaryDirectory() as tempdir: with utils.TemporaryDirectory() as tempdir:
entity = 'tests/samples/codefiles/emptyfile.txt' entity = 'tests/samples/codefiles/emptyfile.txt'
@ -447,9 +435,7 @@ class MainTestCase(utils.TestCase):
def test_nonascii_filename(self, logs): def test_nonascii_filename(self, logs):
logging.disable(logging.NOTSET) logging.disable(logging.NOTSET)
response = Response() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
response.status_code = 201
self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response
with utils.TemporaryDirectory() as tempdir: with utils.TemporaryDirectory() as tempdir:
filename = list(filter(lambda x: x.endswith('.txt'), os.listdir(u('tests/samples/codefiles/unicode'))))[0] filename = list(filter(lambda x: x.endswith('.txt'), os.listdir(u('tests/samples/codefiles/unicode'))))[0]

View file

@ -13,10 +13,10 @@ import time
import uuid import uuid
from testfixtures import log_capture from testfixtures import log_capture
from wakatime.compat import u 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 wakatime.packages.requests.models import Response
from . import utils from . import utils
from .utils import ANY, json from .utils import ANY, json, CustomResponse
class OfflineQueueTestCase(utils.TestCase): class OfflineQueueTestCase(utils.TestCase):
@ -84,7 +84,9 @@ class OfflineQueueTestCase(utils.TestCase):
args = ['--file', entity, '--config', config, '--time', now] args = ['--file', entity, '--config', config, '--time', now]
execute(args) 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) execute(args)
queue = Queue(None, None) queue = Queue(None, None)
@ -121,7 +123,10 @@ class OfflineQueueTestCase(utils.TestCase):
entity3 = 'tests/samples/codefiles/python.py' entity3 = 'tests/samples/codefiles/python.py'
project3 = 'proj3' project3 = 'proj3'
args = ['--file', entity3, '--config', config, '--time', now3, '--project', project3] 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) execute(args)
# offline queue should be empty # offline queue should be empty
@ -184,21 +189,9 @@ class OfflineQueueTestCase(utils.TestCase):
key = str(uuid.uuid4()) 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'] 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 = 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 self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response
with utils.mock.patch('wakatime.main.sys.stdin') as mock_stdin: with utils.mock.patch('wakatime.main.sys.stdin') as mock_stdin:
@ -279,21 +272,64 @@ class OfflineQueueTestCase(utils.TestCase):
key = str(uuid.uuid4()) 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'] 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 with utils.mock.patch('wakatime.main.sys.stdin') as mock_stdin:
def status_code(self): heartbeats = json.dumps([{
return 202 '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 retval = execute(args)
def status_code(self, value): self.assertEquals(retval, SUCCESS)
pass self.assertNothingPrinted()
@property expected = 'WakaTime WARNING Results from api not matching heartbeats sent.'
def text(self): actual = self.getLogOutput(logs)
return '[[{"id":1},201], [{"error":"error 2"},500], [{"id":3},201], [{"error":4},500]]' 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 = 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 self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response
with utils.mock.patch('wakatime.main.sys.stdin') as mock_stdin: 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) self.assertEquals(queue._get_db_file(), fh.name)
saved_heartbeats = queue.pop_many() saved_heartbeats = queue.pop_many()
self.assertNothingPrinted() 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 expected = "WakaTime WARNING Missing 4 results from api.\nWakaTime WARNING Missing 2 results from api."
self.assertEquals(len(saved_heartbeats), 1) 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): def test_auth_error_when_sending_offline_heartbeats(self):
with utils.NamedTemporaryFile() as fh: with utils.NamedTemporaryFile() as fh:
@ -349,30 +388,20 @@ class OfflineQueueTestCase(utils.TestCase):
project3 = 'proj3' project3 = 'proj3'
args = ['--file', entity3, '--config', config, '--time', now3, '--project', project3] 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 = 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 self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response
retval = execute(args) 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) queue = Queue(None, None)
saved_heartbeat = queue.pop() saved_heartbeats = queue.pop_many()
self.assertNothingPrinted() self.assertNothingPrinted()
self.assertIsNone(saved_heartbeat) self.assertEquals(len(saved_heartbeats), 2)
def test_500_error_when_sending_offline_heartbeats(self): def test_500_error_when_sending_offline_heartbeats(self):
with utils.NamedTemporaryFile() as fh: with utils.NamedTemporaryFile() as fh:
@ -405,30 +434,20 @@ class OfflineQueueTestCase(utils.TestCase):
project3 = 'proj3' project3 = 'proj3'
args = ['--file', entity3, '--config', config, '--time', now3, '--project', project3] 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 = 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 self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response
retval = execute(args) 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) queue = Queue(None, None)
saved_heartbeat = queue.pop() saved_heartbeats = queue.pop_many()
self.assertNothingPrinted() self.assertNothingPrinted()
self.assertIsNone(saved_heartbeat) self.assertEquals(len(saved_heartbeats), 2)
def test_empty_project_can_be_saved(self): def test_empty_project_can_be_saved(self):
with utils.NamedTemporaryFile() as fh: with utils.NamedTemporaryFile() as fh:

View file

@ -18,7 +18,7 @@ from wakatime.constants import API_ERROR, SUCCESS
from wakatime.exceptions import NotYetImplemented from wakatime.exceptions import NotYetImplemented
from wakatime.projects.base import BaseProject from wakatime.projects.base import BaseProject
from . import utils from . import utils
from .utils import ANY, json from .utils import ANY, CustomResponse, json
class ProjectTestCase(utils.TestCase): 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=[]): def shared(self, expected_project='', expected_branch=ANY, entity='', config='good_config.cfg', extra_args=[]):
response = Response() self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = CustomResponse()
response.status_code = 201
self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response
config = os.path.join('tests/samples/configs', config) config = os.path.join('tests/samples/configs', config)
if not os.path.exists(entity): if not os.path.exists(entity):

View file

@ -11,9 +11,10 @@ import sys
from testfixtures import log_capture from testfixtures import log_capture
from wakatime.compat import u from wakatime.compat import u
from wakatime.constants import API_ERROR, SUCCESS 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.exceptions import RequestException
from wakatime.packages.requests.models import Response
from . import utils from . import utils
from .utils import CustomResponse
try: try:
from mock import ANY, call from mock import ANY, call
@ -34,8 +35,7 @@ class ProxyTestCase(utils.TestCase):
] ]
def test_proxy_without_protocol(self): def test_proxy_without_protocol(self):
response = Response() response = CustomResponse()
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 = response
with utils.TemporaryDirectory() as tempdir: 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) 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): def test_https_proxy(self):
response = Response() response = CustomResponse()
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 = response
with utils.TemporaryDirectory() as tempdir: 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) 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): def test_socks_proxy(self):
response = Response() response = CustomResponse()
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 = response
with utils.TemporaryDirectory() as tempdir: with utils.TemporaryDirectory() as tempdir:
@ -225,8 +223,7 @@ class ProxyTestCase(utils.TestCase):
def test_invalid_proxy(self, logs): def test_invalid_proxy(self, logs):
logging.disable(logging.NOTSET) logging.disable(logging.NOTSET)
response = Response() response = CustomResponse()
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 = response
with utils.TemporaryDirectory() as tempdir: with utils.TemporaryDirectory() as tempdir:

View file

@ -6,6 +6,7 @@ import sys
import tempfile import tempfile
from wakatime.compat import u from wakatime.compat import u
from wakatime.packages.requests.models import Response
try: try:
@ -134,6 +135,9 @@ class TestCase(unittest.TestCase):
self.assertEquals(sys.stdout.getvalue(), '') self.assertEquals(sys.stdout.getvalue(), '')
self.assertEquals(sys.stderr.getvalue(), '') self.assertEquals(sys.stderr.getvalue(), '')
def getPrintedOutput(self):
return sys.stdout.getvalue() or '' + sys.stderr.getvalue() or ''
def assertNothingLogged(self, logs): def assertNothingLogged(self, logs):
self.assertEquals(self.getLogOutput(logs), '') self.assertEquals(self.getLogOutput(logs), '')
@ -219,3 +223,31 @@ class DynamicIterable(object):
def next(self): def next(self):
return self.__next__() 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

View file

@ -161,7 +161,7 @@ def _process_server_results(heartbeats, code, content, results, args, configs):
for i in range(len(results)): for i in range(len(results)):
if len(heartbeats) <= i: if len(heartbeats) <= i:
log.debug('Results from server do not match heartbeats sent.') log.warn('Results from api not matching heartbeats sent.')
break break
try: try:
@ -177,6 +177,12 @@ def _process_server_results(heartbeats, code, content, results, args, configs):
if not _success(c): if not _success(c):
_handle_unsent_heartbeats([heartbeats[i]], c, text, args, configs) _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): def _handle_unsent_heartbeats(heartbeats, code, content, args, configs):
if args.offline: if args.offline: