add new AUTH_ERROR exit status to signal an invalid api key. fixes #41.

This commit is contained in:
Alan Hamlett 2016-01-25 23:49:37 +01:00
parent 98de22c3a8
commit 33a87b9877
4 changed files with 118 additions and 48 deletions

View file

@ -1,5 +1,5 @@
Traceback (most recent call last): Traceback (most recent call last):
File "{file}", line 230, in parseArguments File "{file}", line {lineno}, in parseArguments
args.timeout = int(configs.get('settings', 'timeout')) args.timeout = int(configs.get('settings', 'timeout'))
ValueError: invalid literal for int() with base 10: 'abc' ValueError: invalid literal for int() with base 10: 'abc'

View file

@ -6,8 +6,15 @@ from wakatime.packages import requests
import os import os
import time import time
import re
import sys import sys
from wakatime.compat import u from wakatime.compat import u
from wakatime.constants import (
API_ERROR,
AUTH_ERROR,
CONFIG_FILE_PARSE_ERROR,
SUCCESS,
)
from wakatime.packages.requests.models import Response from wakatime.packages.requests.models import Response
from . import utils from . import utils
@ -54,7 +61,7 @@ class BaseTestCase(utils.TestCase):
args = ['--file', entity, '--key', '123', '--config', config] args = ['--file', entity, '--key', '123', '--config', config]
retval = execute(args) retval = execute(args)
self.assertEquals(retval, 0) self.assertEquals(retval, SUCCESS)
self.assertEquals(sys.stdout.getvalue(), '') self.assertEquals(sys.stdout.getvalue(), '')
self.assertEquals(sys.stderr.getvalue(), '') self.assertEquals(sys.stderr.getvalue(), '')
@ -107,10 +114,11 @@ class BaseTestCase(utils.TestCase):
config = 'tests/samples/configs/has_everything.cfg' config = 'tests/samples/configs/has_everything.cfg'
args = ['--file', entity, '--config', config] args = ['--file', entity, '--config', config]
retval = execute(args) retval = execute(args)
self.assertEquals(retval, 0) self.assertEquals(retval, SUCCESS)
expected_stdout = open('tests/samples/output/main_test_good_config_file').read() expected_stdout = open('tests/samples/output/main_test_good_config_file').read()
traceback_file = os.path.realpath('wakatime/main.py') traceback_file = os.path.realpath('wakatime/main.py')
self.assertEquals(sys.stdout.getvalue(), expected_stdout.format(file=traceback_file)) lineno = int(re.search(r' line (\d+),', sys.stdout.getvalue()).group(1))
self.assertEquals(sys.stdout.getvalue(), expected_stdout.format(file=traceback_file, lineno=lineno))
self.assertEquals(sys.stderr.getvalue(), '') self.assertEquals(sys.stderr.getvalue(), '')
self.patched['wakatime.session_cache.SessionCache.get'].assert_called_once_with() self.patched['wakatime.session_cache.SessionCache.get'].assert_called_once_with()
@ -129,7 +137,7 @@ class BaseTestCase(utils.TestCase):
config = 'tests/samples/configs/sample_alternate_apikey.cfg' config = 'tests/samples/configs/sample_alternate_apikey.cfg'
args = ['--file', entity, '--config', config] args = ['--file', entity, '--config', config]
retval = execute(args) retval = execute(args)
self.assertEquals(retval, 0) self.assertEquals(retval, SUCCESS)
self.assertEquals(sys.stdout.getvalue(), '') self.assertEquals(sys.stdout.getvalue(), '')
self.assertEquals(sys.stderr.getvalue(), '') self.assertEquals(sys.stderr.getvalue(), '')
@ -145,7 +153,7 @@ class BaseTestCase(utils.TestCase):
config = 'tests/samples/configs/bad_config.cfg' config = 'tests/samples/configs/bad_config.cfg'
args = ['--file', entity, '--config', config] args = ['--file', entity, '--config', config]
retval = execute(args) retval = execute(args)
self.assertEquals(retval, 103) self.assertEquals(retval, CONFIG_FILE_PARSE_ERROR)
self.assertIn('ParsingError', sys.stdout.getvalue()) self.assertIn('ParsingError', sys.stdout.getvalue())
self.assertEquals(sys.stderr.getvalue(), '') self.assertEquals(sys.stderr.getvalue(), '')
self.patched['wakatime.offlinequeue.Queue.push'].assert_not_called() self.patched['wakatime.offlinequeue.Queue.push'].assert_not_called()
@ -165,7 +173,7 @@ class BaseTestCase(utils.TestCase):
args = ['--file', entity, '--key', '123', '--config', config, '--time', now] args = ['--file', entity, '--key', '123', '--config', config, '--time', now]
retval = execute(args) retval = execute(args)
self.assertEquals(retval, 102) self.assertEquals(retval, API_ERROR)
self.assertEquals(sys.stdout.getvalue(), '') self.assertEquals(sys.stdout.getvalue(), '')
self.assertEquals(sys.stderr.getvalue(), '') self.assertEquals(sys.stderr.getvalue(), '')
@ -206,7 +214,7 @@ class BaseTestCase(utils.TestCase):
args = ['--file', entity, '--key', '123', '--config', config, '--time', now] args = ['--file', entity, '--key', '123', '--config', config, '--time', now]
retval = execute(args) retval = execute(args)
self.assertEquals(retval, 102) self.assertEquals(retval, API_ERROR)
self.assertEquals(sys.stdout.getvalue(), '') self.assertEquals(sys.stdout.getvalue(), '')
self.assertEquals(sys.stderr.getvalue(), '') self.assertEquals(sys.stderr.getvalue(), '')
@ -266,7 +274,7 @@ class BaseTestCase(utils.TestCase):
retval = execute(args) retval = execute(args)
self.assertEquals(retval, 102) self.assertEquals(retval, API_ERROR)
self.assertEquals(sys.stdout.getvalue(), '') self.assertEquals(sys.stdout.getvalue(), '')
self.assertEquals(sys.stderr.getvalue(), '') self.assertEquals(sys.stderr.getvalue(), '')
@ -307,7 +315,7 @@ class BaseTestCase(utils.TestCase):
retval = execute(args) retval = execute(args)
self.assertEquals(retval, 102) self.assertEquals(retval, API_ERROR)
self.assertEquals(sys.stdout.getvalue(), '') self.assertEquals(sys.stdout.getvalue(), '')
self.assertEquals(sys.stderr.getvalue(), '') self.assertEquals(sys.stderr.getvalue(), '')
@ -318,6 +326,47 @@ class BaseTestCase(utils.TestCase):
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_401_response(self):
response = Response()
response.status_code = 401
self.patched['wakatime.packages.requests.adapters.HTTPAdapter.send'].return_value = response
now = u(int(time.time()))
args = ['--file', 'tests/samples/codefiles/twolinefile.txt', '--key', '123',
'--config', 'tests/samples/configs/paranoid.cfg', '--time', now]
retval = execute(args)
self.assertEquals(retval, AUTH_ERROR)
self.assertEquals(sys.stdout.getvalue(), '')
self.assertEquals(sys.stderr.getvalue(), '')
self.patched['wakatime.session_cache.SessionCache.delete'].assert_called_once_with()
self.patched['wakatime.session_cache.SessionCache.get'].assert_called_once_with()
self.patched['wakatime.session_cache.SessionCache.save'].assert_not_called()
heartbeat = {
'language': 'Text only',
'lines': 2,
'entity': 'HIDDEN.txt',
'project': os.path.basename(os.path.abspath('.')),
'branch': os.environ.get('TRAVIS_COMMIT', ANY),
'time': float(now),
'type': 'file',
}
stats = {
u('cursorpos'): None,
u('dependencies'): [],
u('language'): u('Text only'),
u('lineno'): None,
u('lines'): 2,
}
self.patched['wakatime.offlinequeue.Queue.push'].assert_called_once_with(heartbeat, ANY, None)
self.assertEquals(stats, json.loads(self.patched['wakatime.offlinequeue.Queue.push'].call_args[0][1]))
self.patched['wakatime.offlinequeue.Queue.pop'].assert_not_called()
def test_alternate_project(self): def test_alternate_project(self):
response = Response() response = Response()
response.status_code = 0 response.status_code = 0
@ -330,7 +379,7 @@ class BaseTestCase(utils.TestCase):
args = ['--file', entity, '--alternate-project', 'xyz', '--config', config, '--time', now] args = ['--file', entity, '--alternate-project', 'xyz', '--config', config, '--time', now]
retval = execute(args) retval = execute(args)
self.assertEquals(retval, 102) self.assertEquals(retval, API_ERROR)
self.assertEquals(sys.stdout.getvalue(), '') self.assertEquals(sys.stdout.getvalue(), '')
self.assertEquals(sys.stderr.getvalue(), '') self.assertEquals(sys.stderr.getvalue(), '')
@ -371,7 +420,7 @@ class BaseTestCase(utils.TestCase):
args = ['--file', entity, '--project', 'xyz', '--config', config, '--time', now] args = ['--file', entity, '--project', 'xyz', '--config', config, '--time', now]
retval = execute(args) retval = execute(args)
self.assertEquals(retval, 102) self.assertEquals(retval, API_ERROR)
self.assertEquals(sys.stdout.getvalue(), '') self.assertEquals(sys.stdout.getvalue(), '')
self.assertEquals(sys.stderr.getvalue(), '') self.assertEquals(sys.stderr.getvalue(), '')
@ -409,7 +458,7 @@ class BaseTestCase(utils.TestCase):
config = 'tests/samples/configs/good_config.cfg' config = 'tests/samples/configs/good_config.cfg'
args = ['--file', entity, '--config', config] args = ['--file', entity, '--config', config]
retval = execute(args) retval = execute(args)
self.assertEquals(retval, 0) self.assertEquals(retval, SUCCESS)
self.assertEquals(sys.stdout.getvalue(), '') self.assertEquals(sys.stdout.getvalue(), '')
self.assertEquals(sys.stderr.getvalue(), '') self.assertEquals(sys.stderr.getvalue(), '')
@ -429,7 +478,7 @@ class BaseTestCase(utils.TestCase):
config = 'tests/samples/configs/good_config.cfg' config = 'tests/samples/configs/good_config.cfg'
args = ['--file', entity, '--config', config, '--proxy', 'localhost:1234'] args = ['--file', entity, '--config', config, '--proxy', 'localhost:1234']
retval = execute(args) retval = execute(args)
self.assertEquals(retval, 0) self.assertEquals(retval, SUCCESS)
self.assertEquals(sys.stdout.getvalue(), '') self.assertEquals(sys.stdout.getvalue(), '')
self.assertEquals(sys.stderr.getvalue(), '') self.assertEquals(sys.stderr.getvalue(), '')
@ -454,7 +503,7 @@ class BaseTestCase(utils.TestCase):
args = ['--entity', entity, '--entitytype', 'domain', '--config', config, '--time', now] args = ['--entity', entity, '--entitytype', 'domain', '--config', config, '--time', now]
retval = execute(args) retval = execute(args)
self.assertEquals(retval, 102) self.assertEquals(retval, API_ERROR)
self.assertEquals(sys.stdout.getvalue(), '') self.assertEquals(sys.stdout.getvalue(), '')
self.assertEquals(sys.stderr.getvalue(), '') self.assertEquals(sys.stderr.getvalue(), '')
@ -491,7 +540,7 @@ class BaseTestCase(utils.TestCase):
args = ['--entity', entity, '--entitytype', 'app', '--config', config, '--time', now] args = ['--entity', entity, '--entitytype', 'app', '--config', config, '--time', now]
retval = execute(args) retval = execute(args)
self.assertEquals(retval, 102) self.assertEquals(retval, API_ERROR)
self.assertEquals(sys.stdout.getvalue(), '') self.assertEquals(sys.stdout.getvalue(), '')
self.assertEquals(sys.stderr.getvalue(), '') self.assertEquals(sys.stderr.getvalue(), '')

View file

@ -13,3 +13,4 @@
SUCCESS = 0 SUCCESS = 0
API_ERROR = 102 API_ERROR = 102
CONFIG_FILE_PARSE_ERROR = 103 CONFIG_FILE_PARSE_ERROR = 103
AUTH_ERROR = 104

View file

@ -30,7 +30,12 @@ sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), 'pac
from .__about__ import __version__ from .__about__ import __version__
from .compat import u, open, is_py3 from .compat import u, open, is_py3
from .constants import SUCCESS, API_ERROR, CONFIG_FILE_PARSE_ERROR from .constants import (
API_ERROR,
AUTH_ERROR,
CONFIG_FILE_PARSE_ERROR,
SUCCESS,
)
from .logger import setup_logging from .logger import setup_logging
from .offlinequeue import Queue from .offlinequeue import Queue
from .packages import argparse from .packages import argparse
@ -289,6 +294,9 @@ def send_heartbeat(project=None, branch=None, hostname=None, stats={}, key=None,
timestamp=None, isWrite=None, plugin=None, offline=None, entity_type='file', timestamp=None, isWrite=None, plugin=None, offline=None, entity_type='file',
hidefilenames=None, proxy=None, api_url=None, timeout=None, **kwargs): hidefilenames=None, proxy=None, api_url=None, timeout=None, **kwargs):
"""Sends heartbeat as POST request to WakaTime api server. """Sends heartbeat as POST request to WakaTime api server.
Returns `SUCCESS` when heartbeat was sent, otherwise returns an
error code constant.
""" """
if not api_url: if not api_url:
@ -375,7 +383,7 @@ def send_heartbeat(project=None, branch=None, hostname=None, stats={}, key=None,
'response_code': response_code, 'response_code': response_code,
}) })
session_cache.save(session) session_cache.save(session)
return True return SUCCESS
if offline: if offline:
if response_code != 400: if response_code != 400:
queue = Queue() queue = Queue()
@ -385,6 +393,8 @@ def send_heartbeat(project=None, branch=None, hostname=None, stats={}, key=None,
'response_code': response_code, 'response_code': response_code,
'response_content': response_content, 'response_content': response_content,
}) })
session_cache.delete()
return AUTH_ERROR
elif log.isEnabledFor(logging.DEBUG): elif log.isEnabledFor(logging.DEBUG):
log.warn({ log.warn({
'response_code': response_code, 'response_code': response_code,
@ -401,7 +411,39 @@ def send_heartbeat(project=None, branch=None, hostname=None, stats={}, key=None,
'response_content': response_content, 'response_content': response_content,
}) })
session_cache.delete() session_cache.delete()
return False return API_ERROR
def sync_offline_heartbeats(args, hostname):
"""Sends all heartbeats which were cached in the offline Queue."""
queue = Queue()
while True:
heartbeat = queue.pop()
if heartbeat is None:
break
status = send_heartbeat(
project=heartbeat['project'],
entity=heartbeat['entity'],
timestamp=heartbeat['time'],
branch=heartbeat['branch'],
hostname=hostname,
stats=json.loads(heartbeat['stats']),
key=args.key,
isWrite=heartbeat['is_write'],
plugin=heartbeat['plugin'],
offline=args.offline,
hidefilenames=args.hidefilenames,
entity_type=heartbeat['type'],
proxy=args.proxy,
api_url=args.api_url,
timeout=args.timeout,
)
if status != SUCCESS:
if status == AUTH_ERROR:
return AUTH_ERROR
break
return SUCCESS
def execute(argv=None): def execute(argv=None):
@ -438,37 +480,15 @@ def execute(argv=None):
kwargs['project'] = project kwargs['project'] = project
kwargs['branch'] = branch kwargs['branch'] = branch
kwargs['stats'] = stats kwargs['stats'] = stats
kwargs['hostname'] = args.hostname or socket.gethostname() hostname = args.hostname or socket.gethostname()
kwargs['hostname'] = hostname
kwargs['timeout'] = args.timeout kwargs['timeout'] = args.timeout
if send_heartbeat(**kwargs): status = send_heartbeat(**kwargs)
queue = Queue() if status == SUCCESS:
while True: return sync_offline_heartbeats(args, hostname)
heartbeat = queue.pop() else:
if heartbeat is None: return status
break
sent = send_heartbeat(
project=heartbeat['project'],
entity=heartbeat['entity'],
timestamp=heartbeat['time'],
branch=heartbeat['branch'],
hostname=kwargs['hostname'],
stats=json.loads(heartbeat['stats']),
key=args.key,
isWrite=heartbeat['is_write'],
plugin=heartbeat['plugin'],
offline=args.offline,
hidefilenames=args.hidefilenames,
entity_type=heartbeat['type'],
proxy=args.proxy,
api_url=args.api_url,
timeout=args.timeout,
)
if not sent:
break
return SUCCESS
return API_ERROR
else: else:
log.debug('File does not exist; ignoring this heartbeat.') log.debug('File does not exist; ignoring this heartbeat.')