From 4c02060a39ba51a90e39f0554e73f23954f284f2 Mon Sep 17 00:00:00 2001 From: Herwin van Welbergen <hvanwelbergen@TechFak.Uni-Bielefeld.DE> Date: Thu, 20 Dec 2012 17:50:14 +0100 Subject: [PATCH] python notifier --- .../ComponentNotifierIntegrationTest.java | 53 ++++---- ipaacalib/python/src/notifier.py | 75 +++++++++++ ipaacalib/python/test/ivy.xml | 3 +- ipaacalib/python/test/src/testnotifier.py | 123 ++++++++++++++++++ 4 files changed, 229 insertions(+), 25 deletions(-) create mode 100644 ipaacalib/python/src/notifier.py create mode 100644 ipaacalib/python/test/src/testnotifier.py diff --git a/ipaacalib/java/test/src/ipaaca/util/ComponentNotifierIntegrationTest.java b/ipaacalib/java/test/src/ipaaca/util/ComponentNotifierIntegrationTest.java index 334f2ec..aef0e5a 100644 --- a/ipaacalib/java/test/src/ipaaca/util/ComponentNotifierIntegrationTest.java +++ b/ipaacalib/java/test/src/ipaaca/util/ComponentNotifierIntegrationTest.java @@ -21,74 +21,79 @@ import com.google.common.collect.ImmutableSet; /** * Integration test for the ComponentNotifier, connects two of them. Requires a running spread daemon. * @author hvanwelbergen - * + * */ -public class ComponentNotifierIntegrationTest +public class ComponentNotifierIntegrationTest { private ComponentNotifier notifier1; private ComponentNotifier notifier2; private InputBuffer inBuffer; private OutputBuffer outBuffer; - + static { Initializer.initializeIpaacaRsb(); } - + private class MyHandlerFunctor implements HandlerFunctor { @Getter private volatile int numCalled = 0; - + @Override public void handle(AbstractIU iu, IUEventType type, boolean local) { - numCalled++; - } + numCalled++; + } } - + @After public void after() { - inBuffer.close(); - outBuffer.close(); + if (inBuffer != null) + { + inBuffer.close(); + } + if (outBuffer != null) + { + outBuffer.close(); + } } - + private ComponentNotifier setupCompNotifier(String id, Set<String> sendList, Set<String> recvList) { - inBuffer = new InputBuffer(id+"in", ImmutableSet.of(ComponentNotifier.NOTIFY_CATEGORY)); - outBuffer = new OutputBuffer(id+"out"); + inBuffer = new InputBuffer(id + "in", ImmutableSet.of(ComponentNotifier.NOTIFY_CATEGORY)); + outBuffer = new OutputBuffer(id + "out"); return new ComponentNotifier(id, "test", ImmutableSet.copyOf(sendList), ImmutableSet.copyOf(recvList), outBuffer, inBuffer); } - - + @Test public void testSelf() throws InterruptedException { - notifier1 = setupCompNotifier("not1", ImmutableSet.of("a1","b1"), ImmutableSet.of("a3","b1")); + notifier1 = setupCompNotifier("not1", ImmutableSet.of("a1", "b1"), ImmutableSet.of("a3", "b1")); MyHandlerFunctor h1 = new MyHandlerFunctor(); notifier1.addNotificationHandler(h1); - - notifier1.initialize(); + + notifier1.initialize(); Thread.sleep(500); - assertEquals(0, h1.getNumCalled()); + assertEquals(0, h1.getNumCalled()); } - + @Test public void testTwo() throws InterruptedException { - notifier1 = setupCompNotifier("not1", ImmutableSet.of("a1","b1"), ImmutableSet.of("a3","b2")); - notifier2 = setupCompNotifier("not2", ImmutableSet.of("a2","b2"), ImmutableSet.of("a3","b1")); + notifier1 = setupCompNotifier("not1", ImmutableSet.of("a1", "b1"), ImmutableSet.of("a3", "b2")); + notifier2 = setupCompNotifier("not2", ImmutableSet.of("a2", "b2"), ImmutableSet.of("a3", "b1")); MyHandlerFunctor h1 = new MyHandlerFunctor(); MyHandlerFunctor h2 = new MyHandlerFunctor(); notifier1.addNotificationHandler(h1); notifier2.addNotificationHandler(h2); - + notifier1.initialize(); Thread.sleep(500); notifier2.initialize(); Thread.sleep(500); - + assertEquals(1, h1.getNumCalled()); assertEquals(1, h2.getNumCalled()); } diff --git a/ipaacalib/python/src/notifier.py b/ipaacalib/python/src/notifier.py new file mode 100644 index 0000000..d204c74 --- /dev/null +++ b/ipaacalib/python/src/notifier.py @@ -0,0 +1,75 @@ +''' +Created on Dec 20, 2012 + +@author: hvanwelbergen +''' +from __future__ import with_statement +import threading + +from ipaaca import IUEventType +from ipaaca import Message +class ComponentNotifier(object): + ''' + classdocs + ''' + + NOTIFY_CATEGORY = "componentNotify"; + SEND_CATEGORIES = "send_categories"; + RECEIVE_CATEGORIES = "recv_categories"; + STATE = "state"; + NAME = "name"; + FUNCTION = "function"; + + def __init__(self, componentName, componentFunction, sendCategories, receiveCategories, outBuffer, inBuffer): + ''' + Constructor + ''' + self.componentName = componentName + self.componentFunction = componentFunction + self.sendCategories = frozenset(sendCategories) + self.receiveCategories = frozenset(receiveCategories) + self.inBuffer = inBuffer + self.outBuffer = outBuffer + self.initialized = False + self.notificationHandlers = [] + self.initializeLock = threading.Lock() + self.notificationHandlerLock = threading.Lock() + self.submitLock = threading.Lock() + + def _submit_notify(self, isNew): + with self.submitLock: + notifyIU = Message(ComponentNotifier.NOTIFY_CATEGORY) + notifyIU.payload[ComponentNotifier.NAME] = self.componentName + notifyIU.payload[ComponentNotifier.FUNCTION] = self.componentFunction + notifyIU.payload[ComponentNotifier.SEND_CATEGORIES] = ",".join(self.sendCategories) + notifyIU.payload[ComponentNotifier.RECEIVE_CATEGORIES] = ",".join(self.receiveCategories) + notifyIU.payload[ComponentNotifier.STATE] = "new" if isNew else "old" + + self.outBuffer.add(notifyIU) + + def _handle_iu_event(self, iu, event_type, local): + print("handle, iuname:"+iu.payload[ComponentNotifier.NAME]+" component name: "+self.componentName+" state "+iu.payload[ComponentNotifier.STATE]) + if iu.payload[ComponentNotifier.NAME] == self.componentName: + return + with self.notificationHandlerLock: + for h in self.notificationHandlers: + h(iu, event_type, local) + if iu.payload[ComponentNotifier.STATE] == "new": + print("submitting") + self._submit_notify(False) + + def add_notification_handler(self, handler): + with self.notificationHandlerLock: + self.notificationHandlers.append(handler) + + def initialize(self): + with self.initializeLock: + if (not self.initialized): + self.inBuffer.register_handler(self._handle_iu_event, [IUEventType.MESSAGE], ComponentNotifier.NOTIFY_CATEGORY) + self._submit_notify(True) + self.initialized = True + + + + + \ No newline at end of file diff --git a/ipaacalib/python/test/ivy.xml b/ipaacalib/python/test/ivy.xml index ffa8219..bdf74d7 100644 --- a/ipaacalib/python/test/ivy.xml +++ b/ipaacalib/python/test/ivy.xml @@ -1,6 +1,7 @@ <ivy-module version="2.0"> <info organisation="ipaaca" module="IpaacaPythonTest"/> <dependencies> - <dependency org="hamcrest" name="hamcrest" rev="latest.release"/> + <dependency org="hamcrest" name="hamcrest" rev="latest.release"/> + <dependency org="mockito" name="mockito" rev="latest.release" /> </dependencies> </ivy-module> diff --git a/ipaacalib/python/test/src/testnotifier.py b/ipaacalib/python/test/src/testnotifier.py new file mode 100644 index 0000000..11576a3 --- /dev/null +++ b/ipaacalib/python/test/src/testnotifier.py @@ -0,0 +1,123 @@ +''' +Created on Dec 20, 2012 + +@author: hvanwelbergen +''' +import unittest +from mockito import mock +from mockito import verify +from mockito import any +from mockito import when +from mockito import times +from notifier import ComponentNotifier +from hamcrest.core.base_matcher import BaseMatcher +from ipaaca import IUEventType +from ipaaca import Message +from ipaaca import InputBuffer +from ipaaca import OutputBuffer +import time +import os + +class IUCategoryMatcher(BaseMatcher): + def __init__(self, expected_cat): + self.expected_cat = expected_cat + + def _matches_(self, iu): + return iu.category==self.expected_cat + + def describe_to(self, description): + description.append_text("IU with category :"+self.expected_cat) + +class ComponentNotifierTest(unittest.TestCase): + + RECV_CAT = {"testrec1", "testrc2"} + SEND_CAT = {"testsnd1", "testsnd2", "testsnd3"} + def setUp(self): + self.mockOutBuffer = mock() + self.mockInBuffer = mock() + self.notifier = ComponentNotifier("testcomp","testfunc", ComponentNotifierTest.SEND_CAT, ComponentNotifierTest.RECV_CAT, self.mockOutBuffer, self.mockInBuffer) + self.notifier.initialize() + + def tearDown(self): + pass + + def _sendNotify(self, state, receiveCats): + mockIUNotify = Message(ComponentNotifier.NOTIFY_CATEGORY) + mockIUNotify.payload[ComponentNotifier.STATE] = state; + mockIUNotify.payload[ComponentNotifier.NAME] = "namex"; + mockIUNotify.payload[ComponentNotifier.SEND_CATEGORIES] = ""; + mockIUNotify.payload[ComponentNotifier.RECEIVE_CATEGORIES] = ",".join(receiveCats); + self.notifier._handle_iu_event(mockIUNotify, IUEventType.ADDED, False) + + def testNotifyAtInit(self): + verify(self.mockOutBuffer).add(any()) + #TODO: python mockito cannot yet use hamcrest matchers, so cannot easily test if the message is correct :( + #assertEquals(ComponentNotifier.NOTIFY_CATEGORY, iu.getCategory()); + #assertEquals("new", iu.getPayload().get(ComponentNotifier.STATE)); + #assertThat(ImmutableSet.copyOf(iu.getPayload().get(ComponentNotifier.RECEIVE_CATEGORIES).split(",")), + # IsIterableContainingInAnyOrder.containsInAnyOrder(RECV_CAT.toArray(new String[0]))); + #assertThat(ImmutableSet.copyOf(iu.getPayload().get(ComponentNotifier.SEND_CATEGORIES).split(",")), + # IsIterableContainingInAnyOrder.containsInAnyOrder(SEND_CAT.toArray(new String[0]))); + + def testNotifyAtNotifyNew(self): + self._sendNotify("new", {"testsnd1"}); + verify(self.mockOutBuffer, times(2)).add(any()) + #TODO: python mockito cannot yet use hamcrest matchers, so cannot easily test if the message is correct :( + #ArgumentCaptor<LocalIU> argument = ArgumentCaptor.forClass(LocalIU.class); + #verify(mockOutBuffer, times(2)).add(argument.capture()); + #LocalIU iu = argument.getAllValues().get(1); + #assertEquals("componentNotify", iu.getCategory()); + #assertEquals("old", iu.getPayload().get("state")); + + def testNoNotifyAtNotifyOld(self): + self._sendNotify("old", {"testsnd1"}); + verify(self.mockOutBuffer, times(1)).add(any()) + +class MyListener(object): + def __init__(self): + self.numCalled = 0 + def handle(self, iu, mytype, local): + self.numCalled += 1 + +class ComponentNotifierIntegrationTest(unittest.TestCase): + def setUp(self): + pass + + def tearDown(self): + pass + + def _setupCompNotifier(self, idx, sendList, recvList): + inBuffer = InputBuffer(idx+"in", {ComponentNotifier.NOTIFY_CATEGORY}) + outBuffer = OutputBuffer(idx+"out") + return ComponentNotifier(idx, "testfunction", sendList, recvList, outBuffer, inBuffer) + +# bug: this somehow remains active after running +# def testSelf(self): +# notifier = self._setupCompNotifier("not", {"a1","b1"}, {"a3","b1"}); +# listener = MyListener() +# notifier.add_notification_handler(listener.handle); +# +# notifier.initialize(); +# time.sleep(0.5); +# +# self.assertEquals(0, listener.numCalled); + + def testTwo(self): + notifier1 = self._setupCompNotifier("not1", {"a1", "b1"}, {"a3", "b2"}); + notifier2 = self._setupCompNotifier("not2", {"a2", "b2"}, {"a3", "b1"}); + listener1 = MyListener() + listener2 = MyListener() + notifier1.add_notification_handler(listener1.handle) + notifier2.add_notification_handler(listener2.handle) + + notifier1.initialize() + time.sleep(0.5) + notifier2.initialize() + time.sleep(0.5) + self.assertEqual(1, listener1.numCalled) + self.assertEqual(1, listener2.numCalled) + +if __name__ == "__main__": + #import sys;sys.argv = ['', 'Test.testName'] + unittest.main() + os._exit(0) \ No newline at end of file -- GitLab