Permalink
Browse files

add tests for basic functionality and sync library

  • Loading branch information...
mreiferson committed Feb 6, 2013
1 parent eb57431 commit 8da49e46352c115414817a6235a6752857ce09ec
Showing with 259 additions and 43 deletions.
  1. +1 −0 .gitignore
  2. +0 −24 nsq/BackoffTimer.py
  3. +6 −3 nsq/__init__.py
  4. +6 −3 nsq/nsq.py
  5. +0 −13 nsq/sync.py
  6. +48 −0 tests/mock_socket.py
  7. +62 −0 tests/test_basic.py
  8. +49 −0 tests/test_command.py
  9. +87 −0 tests/test_sync.py
View
@@ -1,3 +1,4 @@
dist
*.pyc
pynsq.egg-info
+build
View
@@ -42,27 +42,3 @@ def failure(self):
def get_interval(self):
return float(self.min_interval + self.short_interval + self.long_interval)
-
-
-def test_timer():
- timer = BackoffTimer(.1, 120, long_length=1000)
- assert timer.get_interval() == .1
- timer.success()
- assert timer.get_interval() == .1
- timer.failure()
- interval = '%0.2f' % timer.get_interval()
- assert interval == '3.19'
- assert timer.min_interval == Decimal('.1')
- assert timer.short_interval == Decimal('2.9975')
- assert timer.long_interval == Decimal('0.089925')
-
- timer.failure()
- interval = '%0.2f' % timer.get_interval()
- assert interval == '6.27'
- timer.success()
- interval = '%0.2f' % timer.get_interval()
- assert interval == '3.19'
- for i in range(25):
- timer.failure()
- interval = '%0.2f' % timer.get_interval()
- assert interval == '32.41'
View
@@ -1,13 +1,16 @@
-from nsq import unpack_response, decode_message, subscribe, ready, finish, requeue, nop
+from nsq import unpack_response, decode_message, identify, subscribe, ready, finish, touch, requeue, nop
+from nsq import valid_topic_name, valid_channel_name
from nsq import FRAME_TYPE_RESPONSE, FRAME_TYPE_ERROR, FRAME_TYPE_MESSAGE, TOUCH, FIN, REQ
+from BackoffTimer import BackoffTimer
from sync import SyncConn
from async import AsyncConn
from NSQReader import Reader, RequeueWithoutBackoff, run
__version__ = '0.3.3-alpha'
__author__ = "Matt Reiferson <snakes@gmail.com>"
-__all__ = ["Reader", "RequeueWithoutBackoff", "run",
+__all__ = ["Reader", "RequeueWithoutBackoff", "run", "BackoffTimer",
"SyncConn", "AsyncConn", "unpack_response", "decode_message",
- "subscribe", "ready", "finish", "requeue", "nop",
+ "identify", "subscribe", "ready", "finish", "touch", "requeue", "nop",
+ "valid_topic_name", "valid_channel_name",
"FRAME_TYPE_RESPONSE", "FRAME_TYPE_ERROR", "FRAME_TYPE_MESSAGE",
"TOUCH", "FIN", "REQ"]
View
@@ -3,7 +3,7 @@
try:
import simplejson as json
except ImportError:
- import json
+ import json # pyflakes.ignore
MAGIC_V2 = " V2"
@@ -80,13 +80,16 @@ def identify(data):
return _command('IDENTIFY', json.dumps(data))
def ready(count):
+ assert isinstance(count, int), "ready count must be an integer"
+ assert count > 0, "ready count cannot be negative"
return _command('RDY', None, str(count))
def finish(id):
return _command('FIN', None, id)
-def requeue(id, time_ms):
- return _command('REQ', None, id, time_ms)
+def requeue(id, time_ms=0):
+ assert isinstance(time_ms, int), "requeue time_ms must be an integer"
+ return _command('REQ', None, id, str(time_ms))
def touch(id):
return _command('TOUCH', None, id)
View
@@ -35,16 +35,3 @@ def read_response(self):
def send(self, data):
self.s.send(data)
-
-
-if __name__ == '__main__':
- c = SyncConn()
- c.connect("127.0.0.1", 4150)
- c.send(nsq.subscribe('test', 'ch', 'a', 'b'))
- for i in xrange(10):
- c.send(nsq.ready(1))
- resp = c.read_response()
- unpacked = nsq.unpack_response(resp)
- msg = nsq.decode_message(unpacked[1])
- print msg.id, msg.body
- c.send(nsq.finish(msg.id))
View
@@ -0,0 +1,48 @@
+"""
+Mock socket module, copied (and edited) from:
+http://svn.python.org/projects/python/branches/pep-0384/Lib/test/mock_socket.py
+"""
+
+
+class MockSocket:
+ def __init__(self):
+ self.output = []
+ self.lines = []
+ self.conn = None
+ self.timeout = None
+
+ def connect(self, addr):
+ pass
+
+ def queue_recv(self, line):
+ self.lines.append(line)
+
+ def recv(self, bufsize, flags=None):
+ return self.lines.pop(0)
+
+ def settimeout(self, timeout=None):
+ if timeout is None:
+ self.timeout = 60
+ else:
+ self.timeout = timeout
+
+ def gettimeout(self):
+ return self.timeout
+
+ def send(self, data, flags=None):
+ self.output.append(data)
+ return len(data)
+
+ def close(self):
+ pass
+
+
+def socket(family=None, type=None, proto=None):
+ return MockSocket()
+
+
+# Constants
+AF_INET = None
+SOCK_STREAM = None
+SOL_SOCKET = None
+SO_REUSEADDR = None
View
@@ -0,0 +1,62 @@
+from decimal import Decimal
+import os
+import sys
+
+# shunt '..' into sys.path since we are in a 'tests' subdirectory
+base_dir = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..'))
+if base_dir not in sys.path:
+ sys.path.insert(0, base_dir)
+
+from nsq import BackoffTimer
+import nsq
+
+
+def pytest_generate_tests(metafunc):
+ if metafunc.function == test_topic_names:
+ for name, good in [
+ ('valid_name', True),
+ ('invalid name with space', False),
+ ('invalid_name_due_to_length_this_is_really_long', False),
+ ('test-with_period.', True),
+ ('test#ephemeral', False),
+ ('test:ephemeral', False),
+ ]:
+ metafunc.addcall(funcargs=dict(name=name, good=good))
+ if metafunc.function == test_channel_names:
+ for name, good in [
+ ('test', True),
+ ('test-with_period.', True),
+ ('test#ephemeral', True),
+ ('invalid_name_due_to_length_this_is_really_long', False),
+ ('invalid name with space', False),
+ ]:
+ metafunc.addcall(funcargs=dict(name=name, good=good))
+
+def test_topic_names(name, good):
+ assert nsq.valid_topic_name(name) == good
+
+def test_channel_names(name, good):
+ assert nsq.valid_channel_name(name) == good
+
+def test_backoff_timer():
+ timer = BackoffTimer(.1, 120, long_length=1000)
+ assert timer.get_interval() == .1
+ timer.success()
+ assert timer.get_interval() == .1
+ timer.failure()
+ interval = '%0.2f' % timer.get_interval()
+ assert interval == '3.19'
+ assert timer.min_interval == Decimal('.1')
+ assert timer.short_interval == Decimal('2.9975')
+ assert timer.long_interval == Decimal('0.089925')
+
+ timer.failure()
+ interval = '%0.2f' % timer.get_interval()
+ assert interval == '6.27'
+ timer.success()
+ interval = '%0.2f' % timer.get_interval()
+ assert interval == '3.19'
+ for i in range(25):
+ timer.failure()
+ interval = '%0.2f' % timer.get_interval()
+ assert interval == '32.41'
View
@@ -0,0 +1,49 @@
+import struct
+import os
+import sys
+try:
+ import simplejson as json
+except ImportError:
+ import json # pyflakes.ignore
+
+# shunt '..' into sys.path since we are in a 'tests' subdirectory
+base_dir = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..'))
+if base_dir not in sys.path:
+ sys.path.insert(0, base_dir)
+
+import nsq
+
+
+def pytest_generate_tests(metafunc):
+ identify_body = json.dumps({'a': 1, 'b': 2})
+ if metafunc.function == test_command:
+ for cmd_method, kwargs, result in [
+ (nsq.identify,
+ {'data': {'a': 1, 'b': 2}},
+ 'IDENTIFY\n' + struct.pack('>l', len(identify_body)) + identify_body),
+ (nsq.subscribe,
+ {'topic': 'test_topic', 'channel': 'test_channel'},
+ 'SUB test_topic test_channel\n'),
+ (nsq.finish,
+ {'id': 'test'},
+ 'FIN test\n'),
+ (nsq.requeue,
+ {'id': 'test'},
+ 'REQ test 0\n'),
+ (nsq.requeue,
+ {'id': 'test', 'time_ms': 60},
+ 'REQ test 60\n'),
+ (nsq.touch,
+ {'id': 'test'},
+ 'TOUCH test\n'),
+ (nsq.ready,
+ {'count': 100},
+ 'RDY 100\n'),
+ (nsq.nop,
+ {},
+ 'NOP\n'),
+ ]:
+ metafunc.addcall(funcargs=dict(cmd_method=cmd_method, kwargs=kwargs, result=result))
+
+def test_command(cmd_method, kwargs, result):
+ assert cmd_method(**kwargs) == result
View
@@ -0,0 +1,87 @@
+import struct
+import time
+import os
+import sys
+try:
+ import simplejson as json
+except ImportError:
+ import json # pyflakes.ignore
+
+# shunt '..' into sys.path since we are in a 'tests' subdirectory
+base_dir = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..'))
+if base_dir not in sys.path:
+ sys.path.insert(0, base_dir)
+
+import mock_socket
+import nsq
+nsq.sync.socket = mock_socket
+
+
+def mock_write(c, data):
+ c.s.queue_recv(data)
+
+def mock_response_write(c, frame_type, data):
+ body_size = 4 + len(data)
+ body_size_packed = struct.pack('>l', body_size)
+ frame_type_packed = struct.pack('>l', frame_type)
+ mock_write(c, body_size_packed + frame_type_packed + data)
+
+def mock_response_write_message(c, timestamp, attempts, id, body):
+ timestamp_packed = struct.pack('>q', timestamp)
+ attempts_packed = struct.pack('>h', attempts)
+ id = "%016d" % id
+ mock_response_write(c, nsq.FRAME_TYPE_MESSAGE, timestamp_packed + attempts_packed + id + body)
+
+def test_sync_authenticate_subscribe():
+ c = nsq.SyncConn()
+ c.connect("127.0.0.1", 4150)
+
+ c.send(nsq.identify({'short_id': 'test', 'long_id': 'test.example'}))
+ c.send(nsq.subscribe('test', 'ch'))
+
+ mock_response_write(c, nsq.FRAME_TYPE_RESPONSE, 'OK')
+ mock_response_write(c, nsq.FRAME_TYPE_RESPONSE, 'OK')
+
+ resp = c.read_response()
+ unpacked = nsq.unpack_response(resp)
+ assert unpacked[0] == nsq.FRAME_TYPE_RESPONSE
+ assert unpacked[1] == 'OK'
+
+ resp = c.read_response()
+ unpacked = nsq.unpack_response(resp)
+ assert unpacked[0] == nsq.FRAME_TYPE_RESPONSE
+ assert unpacked[1] == 'OK'
+
+def test_sync_receive_messages():
+ c = nsq.SyncConn()
+ c.connect("127.0.0.1", 4150)
+
+ c.send(nsq.identify({'short_id': 'test', 'long_id': 'test.example'}))
+ c.send(nsq.subscribe('test', 'ch'))
+
+ mock_response_write(c, nsq.FRAME_TYPE_RESPONSE, 'OK')
+ mock_response_write(c, nsq.FRAME_TYPE_RESPONSE, 'OK')
+
+ resp = c.read_response()
+ unpacked = nsq.unpack_response(resp)
+ assert unpacked[0] == nsq.FRAME_TYPE_RESPONSE
+ assert unpacked[1] == 'OK'
+
+ resp = c.read_response()
+ unpacked = nsq.unpack_response(resp)
+ assert unpacked[0] == nsq.FRAME_TYPE_RESPONSE
+ assert unpacked[1] == 'OK'
+
+ for i in range(10):
+ c.send(nsq.ready(1))
+ body = '{"data": {"test_key": %d}}' % i
+ ts = int(time.time() * 1000 * 1000)
+ mock_response_write_message(c, ts, 0, i, body)
+ resp = c.read_response()
+ unpacked = nsq.unpack_response(resp)
+ assert unpacked[0] == nsq.FRAME_TYPE_MESSAGE
+ msg = nsq.decode_message(unpacked[1])
+ assert msg.timestamp == ts
+ assert msg.id == "%016d" % i
+ assert msg.attempts == 0
+ assert msg.body == body

0 comments on commit 8da49e4

Please sign in to comment.