def test_validate_convert_coordinates(self): worker = Worker(None) data = { 'lon': 2.346303339766483, 'lat': 48.865546846846846, } assert worker.validate_convert_coordinates(data) assert data == { 'lon': 2.346303339766483, 'lat': 48.865546846846846, } # French decimal format data = { 'lon': "2,346303339766483", 'lat': "48,865546846846846", } assert worker.validate_convert_coordinates(data) assert data == { 'lon': 2.346303339766483, 'lat': 48.865546846846846, } data = { 'lon': "2,346 303 339 766 483", 'lat': "48,865 546 846 846 846", } assert not worker.validate_convert_coordinates(data)
def test_check_hash(self, requests_mock): requests_mock.get( 'http://api.tests/users', json={'data': [ { 'name': 'user1', 'apikey': 'key1' }, ]}) redis = fakeredis.FakeStrictRedis() worker = Worker(redis, auth_enabled=True, api_url='http://api.tests', api_key='f4k3') is_valid = worker.check_hash( { 'timestamp': '1', 'operator': 'user1', 'taxi': 'taxi', 'lat': '17', 'lon': '18', 'device': 'mobile', 'status': 'free', 'version': '1', 'hash': '63f3d6cf5f25e96bd085aca81d715a695c9c36e2' }, ('127.0.2.3', 9999)) assert is_valid is True is_valid = worker.check_hash( { 'timestamp': '1', 'operator': 'user1', 'taxi': 'taxi', 'lat': '17', 'lon': '18', 'device': 'mobile', 'status': 'free', 'version': '1', 'hash': 'b4dhash' }, ('127.0.2.3', 9999)) assert is_valid is False assert b'badhash_operators' in redis.keys() assert redis.zrange(b'badhash_operators', 0, -1, withscores=True) == [(b'user1', 1.0)] assert b'badhash_taxis_ids' in redis.keys() assert redis.zrange(b'badhash_taxis_ids', 0, -1, withscores=True) == [(b'taxi', 1.0)] assert b'badhash_ips' in redis.keys() assert redis.zrange(b'badhash_ips', 0, -1, withscores=True) == [(b'127.0.2.3', 1.0)]
def test_geotaxi_error_5xx(self, requests_mock): requests_mock.get('http://api.tests/users', status_code=500) with pytest.raises(requests.exceptions.HTTPError): Worker(None, auth_enabled=True, api_url='http://api.tests', api_key='f4k3')
def test_update_redis(self): redis = fakeredis.FakeRedis() worker = Worker(redis) payload = { 'timestamp': '1', 'operator': 'user1', 'taxi': 'taxi', 'lat': '17', 'lon': '18', 'device': 'mobile', 'status': 'free', 'version': '1', 'hash': 'b4dhash' } fromaddr = ('127.0.3.4', 9132) # fakeredis doesn't implement geoadd. Fake the method. redis.geoadd = mock.MagicMock() # Try to update redis. worker.update_redis(redis, payload, fromaddr) # GEOADD should have been called twice assert redis.geoadd.call_count == 2 redis.geoadd.assert_any_call('geoindex', '18', '17', 'taxi') redis.geoadd.assert_any_call('geoindex_2', '18', '17', 'taxi:user1') # There should be six keys stored (the two GEOADD above are not listed) assert len(redis.keys()) == 3 assert b'taxi:%s' % payload['taxi'].encode('utf8') in redis.keys() assert b'user1' in redis.hgetall('taxi:%s' % payload['taxi']) assert b'timestamps' in redis.keys() assert redis.zrange(b'timestamps', 0, -1) == [b'taxi:user1'] assert b'timestamps_id' in redis.keys() assert redis.zrange(b'timestamps_id', 0, -1) == [b'taxi']
def test_get_api_users_ok(self, requests_mock): requests_mock.get('http://api.tests/users', json={ 'data': [ { 'name': 'user1', 'apikey': 'key1' }, { 'name': 'user2', 'apikey': 'key2' }, ] }) worker = Worker(None, auth_enabled=True, api_url='http://api.tests', api_key='f4k3') users = worker.get_api_users() assert len(users) == 2 assert 'user1' in users and users['user1'] == 'key1' assert 'user2' in users and users['user2'] == 'key2'
def test_parse_message(self): worker = Worker(None) fromaddr = ('127.0.2.3', 8909) # Bad json assert worker.parse_message(b'{badjson', fromaddr) is None # Invalid UTF8 assert worker.parse_message(b'\xff', fromaddr) is None # Empty dict assert worker.parse_message(b'{}', fromaddr) is None # Missing field "hash" assert worker.parse_message( b'''{ "timestamp": "1", "operator": "user1", "taxi": "taxi", "lat": "17", "lon": "18", "device": "mobile", "status": "free", "version": "1", }''', fromaddr) is None # Valid assert isinstance( worker.parse_message( b'''{ "timestamp": "1", "operator": "user1", "taxi": "taxi", "lat": "17", "lon": "18", "device": "mobile", "status": "free", "version": "1", "hash": "b4dhash" }''', fromaddr), dict)
def test_send_fluent(self): fluent = MockFluent() worker = Worker(None, fluent=fluent) worker.send_fluent({'key': 'value'}) assert fluent._records == [('position', {'key': 'value'})]
def main(): parser = argparse.ArgumentParser( add_help=False, formatter_class=argparse.ArgumentDefaultsHelpFormatter ) parser.add_argument( '--help', action='help', default=argparse.SUPPRESS, help=argparse._('show this help message and exit') ) parser.add_argument( '-v', '--verbose', action='store_true', help='Display debug messages' ) parser.add_argument('-h', '--host', type=str, default='127.0.0.1', help='Listen host') parser.add_argument('-p', '--port', type=int, default=8080, help='Listen port') parser.add_argument('-w', '--workers', type=int, default=max(1, multiprocessing.cpu_count() - 1), help='Number of workers') parser.add_argument('--sentry-dsn', type=str, help='Sentry DSN') parser.add_argument('--redis-host', type=str, default='127.0.0.1', help='Redis host') parser.add_argument('--redis-port', type=str, default=6379, help='Redis port') parser.add_argument('--redis-password', type=str, default=None, help='Redis password') parser.add_argument('--disable-fluent', action='store_true', default=False, help='If set, do not send logs to fluent') parser.add_argument('--fluent-host', type=str, default='127.0.0.1', help='Fluentd host') parser.add_argument('--fluent-port', type=int, default=24224, help='Fluentd port') parser.add_argument('--auth-enabled', action='store_true', default=False, help='Enable authentication') parser.add_argument('--api-url', type=str, default='http://127.0.0.1:5000', help='APITaxi URL, used when authentication is enabled to retrieve users') args = parser.parse_args() if args.sentry_dsn: sentry_sdk.init(args.sentry_dsn, traces_sample_rate=1.0) loglevel = logging.DEBUG if args.verbose else logging.INFO logging.config.dictConfig({ 'version': 1, 'disable_existing_loggers': False, 'formatters': { 'default': { '()': FormatWithPID, 'format': '%(asctime)s (pid %(pid)s) %(message)s' } }, 'handlers': { 'console': { 'level': loglevel, 'class': 'logging.StreamHandler', 'formatter': 'default', } }, 'loggers': { '': { 'handlers': ['console'], 'level': loglevel, } } }) if not args.auth_enabled: logger.warning('Authentication is not enabled') api_key = os.getenv('API_KEY') if args.auth_enabled and not api_key: parser.error('--enable-auth is set but API_KEY environment variable is not set') if args.disable_fluent: fluent = None else: fluent = FluentSender('geotaxi', host=args.fluent_host, port=args.fluent_port) redis = Redis( host=args.redis_host, port=args.redis_port, password=args.redis_password, socket_keepalive=True, ) worker = Worker( redis, fluent=fluent, auth_enabled=args.auth_enabled, api_url=args.api_url, api_key=api_key ) run_server(args.workers, args.host, args.port, worker)