def test_subscription(self): service = PubSub('test_subscription') sub = Subscriber('sub') service.subscribe(sub, sub.key, 'topic', sub.cb1) subscriptions = service.subscriptions() self.assertIn('topic', subscriptions) self.assertIn((sub, sub.key, sub.cb1), subscriptions['topic'])
def test_publish_filter(self): service = PubSub('test_publish_filter') subscribers = [Subscriber('sub%d' % i) for i in range(1, 5)] for sub in subscribers: service.subscribe(sub, sub.key, 'topic', sub.cb1) service.publish('topic', 'event1') for sub in subscribers: self.assertIn((sub, Subscriber.cb1, 'topic', 'event1'), log['callbacks']) service.publish('topic', 'event2', subscribers[0].key) for sub in subscribers[:1]: self.assertNotIn((sub, Subscriber.cb1, 'topic', 'event2'), log['callbacks']) for sub in subscribers[1:]: self.assertIn((sub, Subscriber.cb1, 'topic', 'event2'), log['callbacks']) clear_log() service.publish('topic', 'event3', subscribers[0].key, [s.key for s in subscribers[:3]]) for sub in [subscribers[0], subscribers[3]]: self.assertNotIn((sub, Subscriber.cb1, 'topic', 'event3'), log['callbacks']) for sub in subscribers[1:3]: self.assertIn((sub, Subscriber.cb1, 'topic', 'event3'), log['callbacks'])
def test_persistent_subscriptions(self): service = PubSub('test_pseristsent_subscriptions') sub = Subscriber('sub') service.subscribe(sub, sub.key, 'topic', sub.cb1) del service service = PubSub('test_pseristsent_subscriptions') subscriptions = service.subscriptions() self.assertIn('topic', subscriptions) self.assertIn((sub, sub.key, sub.cb1), subscriptions['topic'])
def test_duplicate_subscription(self): service = PubSub('test_duplicate_subscription') sub = Subscriber('sub') local_dict = WeakValueDictionary() service.subscribe(sub, sub.key, 'topic', sub.cb1) service.subscribe(sub, sub.key, 'topic', sub.cb1) subscriptions = service.subscriptions() self.assertIn('topic', subscriptions) self.assertEqual(len(subscriptions['topic']), 1) self.assertIn((sub, sub.key, sub.cb1), subscriptions['topic'])
def test_weak_subscriptions(self): service = PubSub('test_weak_subscriptions') sub = Subscriber('sub') weaksub = weakref.ref(sub) service.subscribe(sub, sub.key, 'topic', sub.cb1) subscriptions = service.subscriptions() self.assertEqual(len(subscriptions), 1) self.assertIn('topic', subscriptions) self.assertIn((sub, sub.key, sub.cb1), subscriptions['topic']) del subscriptions del sub gc.collect() self.assertEqual(weaksub(), None) subscriptions = service.subscriptions() self.assertEqual(len(subscriptions), 0)
def testGeoFeed(self): item = { 'topic': 'T', 'key': 'K', 'latitude': 39, 'longitude': -79 } id = GeoFeed.publish(**item) self.assertEqual(id, item['key']) time.sleep(2) item['key'] = 'L' id = GeoFeed.publish(**item) self.assertEqual(id, item['key']) last_published = '9999' for doc in GeoFeed.list(item['topic']): self.assertLess(doc['published'], last_published) last_published = doc['published'] for doc in GeoFeed.list('NOT_FOUND'): self.assertFalse('Should never get here') doc = GeoFeed.get(item['topic'], item['key']) self.assertIsNotNone(doc) #set up PubSub subscription so that a task is created when an item is published to the feed sub_url = "/pubsub/task" event=GeoFeed._indexname(item['topic']) channel='ProcessNew%s' % item['topic'] sub_data = {'secret': 'SECRET', 'channel': channel, 'pubname': 'key'} PubSub.subscribe (event, sub_url, sub_data) # now publish a new item to the feed. This should trigger creation of a new task in the queue id = GeoFeed.publish(**item) # need to manually process the task queue because we're in test mode response = self.executeTask() # /pubsub/notify self.assertEqual (response.json['status'], 'OK') response = self.executeTask() # /pubsub/task self.assertEqual (response.json['status'], 'OK') # Now make sure there is a task in the queue queue = TaskQueue() lease = queue.lease (channel=channel) self.assertIsNotNone(lease) self.assertEqual(lease['id'], response.json['id']) self.assertEqual(lease['content']['pub_data']['key'], item['key'])
def test_subscription_filter(self): service = PubSub('test_subscription_filter') sub1 = Subscriber('sub1') sub2 = Subscriber('sub2') service.subscribe(sub1, sub1.key, 'topic1', sub1.cb1) service.subscribe(sub1, sub1.key, 'topic1', sub1.cb2) service.subscribe(sub1, sub1.key, 'topic2', sub1.cb1) service.subscribe(sub1, sub1.key, 'topic2', sub1.cb2) service.subscribe(sub2, sub2.key, 'topic1', sub2.cb1) service.subscribe(sub2, sub2.key, 'topic1', sub2.cb2) service.subscribe(sub2, sub2.key, 'topic2', sub2.cb1) service.subscribe(sub2, sub2.key, 'topic2', sub2.cb2) subscriptions = service.subscriptions(subscriber=sub2) self.assertEqual(len(subscriptions), 2) self.assertIn('topic1', subscriptions) self.assertNotIn((sub1, sub1.key, sub1.cb1), subscriptions['topic1']) self.assertNotIn((sub1, sub1.key, sub1.cb2), subscriptions['topic1']) self.assertIn((sub2, sub2.key, sub2.cb1), subscriptions['topic1']) self.assertIn((sub2, sub2.key, sub2.cb2), subscriptions['topic1']) self.assertIn('topic2', subscriptions) self.assertNotIn((sub1, sub1.key, sub1.cb1), subscriptions['topic2']) self.assertNotIn((sub1, sub1.key, sub1.cb2), subscriptions['topic2']) self.assertIn((sub2, sub2.key, sub2.cb1), subscriptions['topic2']) self.assertIn((sub2, sub2.key, sub2.cb2), subscriptions['topic2']) subscriptions = service.subscriptions(key=sub1.key) self.assertEqual(len(subscriptions), 2) self.assertIn('topic1', subscriptions) self.assertIn((sub1, sub1.key, sub1.cb1), subscriptions['topic1']) self.assertIn((sub1, sub1.key, sub1.cb2), subscriptions['topic1']) self.assertNotIn((sub2, sub2.key, sub2.cb1), subscriptions['topic1']) self.assertNotIn((sub2, sub2.key, sub2.cb2), subscriptions['topic1']) self.assertIn('topic2', subscriptions) self.assertIn((sub1, sub1.key, sub1.cb1), subscriptions['topic2']) self.assertIn((sub1, sub1.key, sub1.cb2), subscriptions['topic2']) self.assertNotIn((sub2, sub2.key, sub2.cb1), subscriptions['topic2']) self.assertNotIn((sub2, sub2.key, sub2.cb2), subscriptions['topic2']) subscriptions = service.subscriptions(topic='topic1') self.assertEqual(len(subscriptions), 1) self.assertIn('topic1', subscriptions) self.assertIn((sub1, sub1.key, sub1.cb1), subscriptions['topic1']) self.assertIn((sub1, sub1.key, sub1.cb2), subscriptions['topic1']) self.assertIn((sub2, sub2.key, sub2.cb1), subscriptions['topic1']) self.assertIn((sub2, sub2.key, sub2.cb2), subscriptions['topic1']) self.assertNotIn('topic2', subscriptions) subscriptions = service.subscriptions(callback=sub1.cb1) self.assertEqual(len(subscriptions), 2) self.assertIn('topic1', subscriptions) self.assertIn((sub1, sub1.key, sub1.cb1), subscriptions['topic1']) self.assertNotIn((sub1, sub1.key, sub1.cb2), subscriptions['topic1']) self.assertNotIn((sub2, sub2.key, sub2.cb1), subscriptions['topic1']) self.assertNotIn((sub2, sub2.key, sub2.cb2), subscriptions['topic1']) self.assertIn('topic2', subscriptions) self.assertIn((sub1, sub1.key, sub1.cb1), subscriptions['topic2']) self.assertNotIn((sub1, sub1.key, sub1.cb2), subscriptions['topic2']) self.assertNotIn((sub2, sub2.key, sub2.cb1), subscriptions['topic2']) self.assertNotIn((sub2, sub2.key, sub2.cb2), subscriptions['topic2'])
def testPubSub(self): sub_data = {'secret': 'SECRET'} id = PubSub.subscribe ('EVENT', 'not_an_url', sub_data) self.assertTrue (PubSub.unsubscribe (id)) self.assertFalse (PubSub.unsubscribe (id)) pub_data = {'message': 123} self.assertEqual(0, PubSub.publish ('EVENT', pub_data)) PubSub.subscribe ('EVENT', 'not_an_url', sub_data) self.assertEqual(1, PubSub.publish ('EVENT', pub_data)) response = self.executeTask() # /pubsub/notify self.assertEqual(response.status_int, 200) response.mustcontain ('unknown url type') url = "/pubsub/test" PubSub.subscribe ('EVENT2', url, sub_data) self.assertEqual(1, PubSub.publish ('EVENT2', pub_data)) response = self.executeTask() # /pubsub/notify self.assertEqual (response.json['status'], 'OK') response = self.executeTask() # /pubsub/test self.assertEqual (response.json['pub_data']["message"], 123) url = "/pubsub/task" sub_data = {'secret': 'SECRET', 'channel': 'CHANNEL', 'taskname': 'NAME'} PubSub.subscribe ('EVENT3', url, sub_data) self.assertEqual(1, PubSub.publish ('EVENT3', pub_data)) response = self.executeTask() # /pubsub/notify self.assertEqual (response.json['status'], 'OK') response = self.executeTask() # /pubsub/task self.assertEqual (response.json['status'], 'OK') queue = TaskQueue() lease = queue.lease (channel='CHANNEL') self.assertIsNotNone(lease) self.assertEqual(lease['id'], response.json['id'])
def test_mutliple_subscriptions(self): service = PubSub('test_multiple_subscription') sub1 = Subscriber('sub1') sub2 = Subscriber('sub2') service.subscribe(sub1, sub1.key, 'topic1', sub1.cb1) service.subscribe(sub1, sub1.key, 'topic1', sub1.cb2) service.subscribe(sub1, sub1.key, 'topic2', sub1.cb1) service.subscribe(sub1, sub1.key, 'topic2', sub1.cb2) service.subscribe(sub2, sub2.key, 'topic1', sub2.cb1) service.subscribe(sub2, sub2.key, 'topic1', sub2.cb2) service.subscribe(sub2, sub2.key, 'topic2', sub2.cb1) service.subscribe(sub2, sub2.key, 'topic2', sub2.cb2) subscriptions = service.subscriptions() self.assertEqual(len(subscriptions), 2) self.assertIn('topic1', subscriptions) self.assertIn((sub1, sub1.key, sub1.cb1), subscriptions['topic1']) self.assertIn((sub1, sub1.key, sub1.cb2), subscriptions['topic1']) self.assertIn((sub2, sub2.key, sub2.cb1), subscriptions['topic1']) self.assertIn((sub2, sub2.key, sub2.cb2), subscriptions['topic1']) self.assertIn('topic2', subscriptions) self.assertIn((sub1, sub1.key, sub1.cb1), subscriptions['topic2']) self.assertIn((sub1, sub1.key, sub1.cb2), subscriptions['topic2']) self.assertIn((sub2, sub2.key, sub2.cb1), subscriptions['topic2']) self.assertIn((sub2, sub2.key, sub2.cb2), subscriptions['topic2'])
def test_publish(self): def callback(topic, event): log['callbacks'].append((callback, topic, event)) pass service = PubSub('test_publish') sub = Subscriber('sub') service.subscribe(sub, sub.key, 'topic', sub.cb1) service.subscribe(sub, sub.key, 'topic', sub.cb2) service.subscribe(sub, sub.key, 'topic2', sub.cb2) service.subscribe(sub, sub.key, 'topic2', callback) service.publish('topic', 'event') service.publish('topic2', 'event2') self.assertEqual(len(log['callbacks']), 4) self.assertIn((sub, Subscriber.cb1, 'topic', 'event'), log['callbacks']) self.assertIn((sub, Subscriber.cb2, 'topic', 'event'), log['callbacks']) self.assertIn((sub, Subscriber.cb2, 'topic2', 'event2'), log['callbacks']) self.assertIn((callback, 'topic2', 'event2'), log['callbacks'])
def handler(signum, frame): logger.info('got term... raising TermException') raise TermException() signal.signal(signal.SIGTERM, handler) def create_data(): logger.info("callback invoked") return {"data": "here is some data from server"} def make_query_callback(data): logger.info('got request of: %s' % data) ps.publish('return_result', create_data()) return ps = PubSub('AWS', topic_arn=os.environ['AWS_SNS_ARN'], logger=logger) make_query_subscription = ps.subscribe('make_query', callback=make_query_callback) try: while True: time.sleep(100) except: logger.info('terminating... dropping subscriber') make_query_subscription.unsubscribe()
####################################################################################### class Counter: def __init__(self): self.value = 0 def on_button(self, pin): self.value += 1 pubsub.publish('counter', self.value) def on_timer(self): self.value += 100 pubsub.publish('counter', self.value) counter = Counter() pubsub.subscribe('button', counter.on_button) pubsub.subscribe('timer', counter.on_timer) ####################################################################################### from util.octopus import disp7_init d7 = disp7_init() # 8 x 7segment display init def display_num(value): d7.show(value) pubsub.subscribe('counter', display_num)
class PubSubFactory(protocol.ServerFactory): protocol = PubSubProtocol def __init__(self, messageTimeout, subscriptionTimeout, messageFormat): self.pubsub = PubSub(messageTimeout) self.subscriptionTimeout = subscriptionTimeout self.messageFormat = messageFormat def subscribe(self, request): urlComponents = urlparse.urlparse(request.uri) query = urlparse.parse_qs(urlComponents.query) if "channel" not in query: self._reportError(request, "expected 'channel' in the request") return channel = tryParseInt(query["channel"][0], 0) if channel == 0: return self._reportError(request, "'channel' value should be number") query.setdefault("time_from", [0]) timeFrom = tryParseInt(query["time_from"][0], 0) query.setdefault("min_id", [0]) mid = tryParseInt(query["min_id"][0], 0) notify = lambda message: self._notify(request,message) print "parameters", timeFrom, mid self.pubsub.subscribe(channel, notify, request.finish, timeFrom, minId = mid, timeoutSec = self.subscriptionTimeout) # --- Utilities --- def _notify(self, request, message): try: request.setResponseCode(200, "OK") message = self._normalize(message) print "MESSAGE: ", message request.write(message) request.finish() except Exception as e: print "Unhandled Error" print e def _normalize(self, messages): if len(messages) == 0: return self.messageFormat % ("[]", 0) maxId = messages[-1][0] messages = (m for id, m in messages) messages = "[%s]" % ",".join(messages) return self.messageFormat % (messages, maxId) def _reportError(self, request, errorMessage): request.setResponseCode(400, "error") request.responseHeaders.addRawHeader("Content-Type", "text/html") request.write("<H1>Error</H1>") request.write("<p>%s</p>" % errorMessage) request.finish()
def test_unsubscribe(self): service = PubSub('test_unsubscribe') sub1 = Subscriber('sub1') sub2 = Subscriber('sub2') service.subscribe(sub1, sub1.key, 'topic1', sub1.cb1) service.subscribe(sub1, sub1.key, 'topic1', sub1.cb2) service.subscribe(sub1, sub1.key, 'topic2', sub1.cb1) service.subscribe(sub1, sub1.key, 'topic2', sub1.cb2) service.subscribe(sub2, sub2.key, 'topic1', sub2.cb1) service.subscribe(sub2, sub2.key, 'topic1', sub2.cb2) service.subscribe(sub2, sub2.key, 'topic2', sub2.cb1) service.subscribe(sub2, sub2.key, 'topic2', sub2.cb2) subscriptions = service.subscriptions() self.assertEqual(len(subscriptions), 2) self.assertIn('topic1', subscriptions) self.assertIn((sub1, sub1.key, sub1.cb1), subscriptions['topic1']) self.assertIn((sub1, sub1.key, sub1.cb2), subscriptions['topic1']) self.assertIn((sub2, sub2.key, sub2.cb1), subscriptions['topic1']) self.assertIn((sub2, sub2.key, sub2.cb2), subscriptions['topic1']) self.assertIn('topic2', subscriptions) self.assertIn((sub1, sub1.key, sub1.cb1), subscriptions['topic2']) self.assertIn((sub1, sub1.key, sub1.cb2), subscriptions['topic2']) self.assertIn((sub2, sub2.key, sub2.cb1), subscriptions['topic2']) self.assertIn((sub2, sub2.key, sub2.cb2), subscriptions['topic2']) self.assertIn((sub2, sub2.key, sub2.cb2), subscriptions['topic1']) service.unsubscribe(sub2, sub2.key, 'topic2', sub2.cb2) subscriptions = service.subscriptions() self.assertEqual(len(subscriptions), 2) self.assertIn('topic1', subscriptions) self.assertIn((sub1, sub1.key, sub1.cb1), subscriptions['topic1']) self.assertIn((sub1, sub1.key, sub1.cb2), subscriptions['topic1']) self.assertIn((sub2, sub2.key, sub2.cb1), subscriptions['topic1']) self.assertIn((sub2, sub2.key, sub2.cb2), subscriptions['topic1']) self.assertIn('topic2', subscriptions) self.assertIn((sub1, sub1.key, sub1.cb1), subscriptions['topic2']) self.assertIn((sub1, sub1.key, sub1.cb2), subscriptions['topic2']) self.assertIn((sub2, sub2.key, sub2.cb1), subscriptions['topic2']) self.assertNotIn((sub2, sub2.key, sub2.cb2), subscriptions['topic2']) service.unsubscribe(sub1, sub1.key, callback=sub1.cb2) subscriptions = service.subscriptions() self.assertEqual(len(subscriptions), 2) self.assertIn('topic1', subscriptions) self.assertIn((sub1, sub1.key, sub1.cb1), subscriptions['topic1']) self.assertNotIn((sub1, sub1.key, sub1.cb2), subscriptions['topic1']) self.assertIn((sub2, sub2.key, sub2.cb1), subscriptions['topic1']) self.assertIn((sub2, sub2.key, sub2.cb2), subscriptions['topic1']) self.assertIn('topic2', subscriptions) self.assertIn((sub1, sub1.key, sub1.cb1), subscriptions['topic2']) self.assertNotIn((sub1, sub1.key, sub1.cb2), subscriptions['topic2']) self.assertIn((sub2, sub2.key, sub2.cb1), subscriptions['topic2']) self.assertNotIn((sub2, sub2.key, sub2.cb2), subscriptions['topic2']) service.unsubscribe(callback=sub1.cb1) subscriptions = service.subscriptions() self.assertEqual(len(subscriptions), 2) self.assertIn('topic1', subscriptions) self.assertNotIn((sub1, sub1.key, sub1.cb1), subscriptions['topic1']) self.assertNotIn((sub1, sub1.key, sub1.cb2), subscriptions['topic1']) self.assertIn((sub2, sub2.key, sub2.cb1), subscriptions['topic1']) self.assertIn((sub2, sub2.key, sub2.cb2), subscriptions['topic1']) self.assertIn('topic2', subscriptions) self.assertNotIn((sub1, sub1.key, sub1.cb1), subscriptions['topic2']) self.assertNotIn((sub1, sub1.key, sub1.cb2), subscriptions['topic2']) self.assertIn((sub2, sub2.key, sub2.cb1), subscriptions['topic2']) self.assertNotIn((sub2, sub2.key, sub2.cb2), subscriptions['topic2']) service.unsubscribe(callback=sub2.cb1) subscriptions = service.subscriptions() self.assertEqual(len(subscriptions), 1) self.assertIn('topic1', subscriptions) self.assertNotIn((sub1, sub1.key, sub1.cb1), subscriptions['topic1']) self.assertNotIn((sub1, sub1.key, sub1.cb2), subscriptions['topic1']) self.assertNotIn((sub2, sub2.key, sub2.cb1), subscriptions['topic1']) self.assertIn((sub2, sub2.key, sub2.cb2), subscriptions['topic1']) self.assertNotIn('topic2', subscriptions) service.unsubscribe() subscriptions = service.subscriptions() self.assertEqual(len(subscriptions), 0)