def test_delete_parent(self): """ When a parent is deleted, the orphan children should be re-parented to the root node. """ world = self.ctx.worlds["base"] nodes = world.scene.nodes parent = Node() child1 = Node() child2 = Node() childchild1 = Node() child1.parent = parent.id child2.parent = parent.id childchild1.parent = child1.id nodes.append([parent, child1, child2, childchild1]) time.sleep(PROPAGATION_TIME) # wait for propagation self.assertEqual(len(nodes), 5) # root node + our 2 nodes self.assertEqual(nodes[child1.id].parent, parent.id) self.assertEqual(nodes[child2.id].parent, parent.id) self.assertEqual(nodes[childchild1.id].parent, child1.id) nodes.remove(parent) time.sleep(PROPAGATION_TIME) # wait for propagation self.assertEqual(len(nodes), 4) # root node + child self.assertEqual(nodes[child1.id].parent, world.scene.rootnode.id) self.assertEqual(nodes[child2.id].parent, world.scene.rootnode.id) self.assertEqual(nodes[childchild1.id].parent, child1.id)
def test_multiple_children(self): world = self.ctx.worlds["base"] nodes = world.scene.nodes parent = Node() child1 = Node() child2 = Node() child3 = Node() child1.parent = parent.id child2.parent = parent.id child3.parent = parent.id nodes.append([parent, child1, child2, child3]) time.sleep(PROPAGATION_TIME) # wait for propagation self.assertEqual(len(nodes), 5) # root node + our nodes self.assertEqual(nodes[child1.id].parent, parent.id) self.assertEqual(nodes[child2.id].parent, parent.id) self.assertEqual(nodes[child3.id].parent, parent.id) nodes.remove(child1) time.sleep(PROPAGATION_TIME) # wait for propagation self.assertEqual(len(nodes), 4) # root node + our nodes self.assertEqual(nodes[child2.id].parent, parent.id) self.assertEqual(nodes[child3.id].parent, parent.id)
def test_propagation_time(nb_worlds, nb_changes): executor = ThreadPoolExecutor(max_workers=nb_worlds) pool = Pool(nb_worlds) pipes = [] res = [] for i in range(nb_worlds - 1): print("Setting up passthrough between world %d and world %d" % (i, i + 1)) #f = executor.submit(passthrough, "world%d" % i, "world%d" % (i+1)) conn1, conn2 = Pipe() pipes.append(conn1) res.append( pool.apply_async( passthrough, ["world%d" % i, "world%d" % (i + 1), conn2])) time.sleep(0.5) ctx = underworlds.Context("test_client") entry_world = ctx.worlds["world0"] exit_world = ctx.worlds["world%d" % (nb_worlds - 1)] future = executor.submit(wait_for_changes, exit_world, nb_changes) print("\n\n\nPropagating %d change(s) from world %s..." % (nb_changes, entry_world)) profileonce("start test with %d worlds" % nb_worlds) for i in range(nb_changes): n = Node() n.name = "node_%d" % i entry_world.scene.append_and_propagate(n) time.sleep(0.01) seen, duration = future.result() profileonce("end test") if seen is None: logger.error("The changes have not been seen!") duration = 0 else: print("It took %s to be notified of the %d change(s) in world %s" % (ms(duration), nb_changes, exit_world)) executor.shutdown(wait=True) for p in pipes: p.send(True) pool.close() pool.join() ctx.close() return duration
def test_adding_nodes(self): world1 = self.ctx1.worlds["base"] world2 = self.ctx2.worlds["base"] # start to wait for changes. # First, we do not perform any change -> should timeout future = self.executor.submit(wait_for_changes, world2) self.assertIsNone(future.result()) # Second, we make a change -> creation of a new node future = self.executor.submit(wait_for_changes, world2) n = Node() n.name = "test" world1.scene.append_and_propagate(n) change = future.result() self.assertIsNotNone(change) #TODO check that the change is either a new node or an update to the root node # (since the new node has been parented to the root node time.sleep( 0.1 ) # sleep a bit to make sure my next 'waitforchanges' is not going to trigger from still pending invalidations # Now, we move the node future = self.executor.submit(wait_for_changes, world2) n.translate([0, 1, 0]) world1.scene.update_and_propagate(n) change = future.result() self.assertIsNotNone(change) self.assertEqual(change[1], UPDATE) self.assertEqual(change[0], [n.id]) # Finally, we remove the node time.sleep( 0.1 ) # sleep a bit to make sure my next 'waitforchanges' is not going to trigger from still pending invalidations future = self.executor.submit(wait_for_changes, world2) world1.scene.remove_and_propagate(n) change = future.result() self.assertIsNotNone(change) self.assertEqual(change[1], DELETE) self.assertEqual(change[0], [n.id]) # Lastly, we do nothing again -> should timeout time.sleep( 0.1 ) # sleep a bit to make sure my next 'waitforchanges' is not going to trigger from still pending invalidations future = self.executor.submit(wait_for_changes, world2) self.assertIsNone(future.result())
def test_propagation_time(nb_worlds, nb_changes): executor = ThreadPoolExecutor(max_workers=nb_worlds) pool = Pool(nb_worlds) pipes = [] res = [] for i in range(nb_worlds-1): print("Setting up passthrough between world %d and world %d" % (i, i+1)) #f = executor.submit(passthrough, "world%d" % i, "world%d" % (i+1)) conn1, conn2 = Pipe() pipes.append(conn1) res.append(pool.apply_async(passthrough, ["world%d" % i, "world%d" % (i+1), conn2])) time.sleep(0.5) ctx = underworlds.Context("test_client") entry_world = ctx.worlds["world0"] exit_world = ctx.worlds["world%d" % (nb_worlds-1)] future = executor.submit(wait_for_changes, exit_world, nb_changes) print("\n\n\nPropagating %d change(s) from world %s..." % (nb_changes, entry_world)) profileonce("start test with %d worlds" % nb_worlds) for i in range(nb_changes): n = Node() n.name = "node_%d" % i entry_world.scene.append_and_propagate(n) time.sleep(0.01) seen, duration = future.result() profileonce("end test") if seen is None: logger.error("The changes have not been seen!") duration = 0 else: print("It took %s to be notified of the %d change(s) in world %s" % (ms(duration), nb_changes, exit_world)) executor.shutdown(wait=True) for p in pipes: p.send(True) pool.close() pool.join() ctx.close() return duration
def test_nodes(self): n = Node() self.assertIsNotNone(n.id) n.name = "test" n.type = MESH serialized = n.serialize() n2 = Node.deserialize(serialized) self.assertEqual(n, n2)
def test_removing_nodes(self): world = self.ctx.worlds["base"] nodes = world.scene.nodes n1 = Node() n1.name = "test1" nodes.update(n1) n2 = Node() n2.name = "test2" nodes.update(n2) n3 = Node() n3.name = "test3" nodes.update(n3) time.sleep(PROPAGATION_TIME) # wait for propagation self.assertEqual(len(nodes), 4) # the 3 added nodes + root node # Get another reference to the 'base' world, and check # our nodes are here. world2 = self.ctx2.worlds["base"] nodes2 = world2.scene.nodes self.assertEqual(len(nodes2), 4) # the 3 added nodes + root node names = [n.name for n in nodes2] # store the order. # Now, remove a node at the end nodes.remove(n3) time.sleep(PROPAGATION_TIME) # wait for propagation self.assertEqual(len(nodes2), 3) names2 = [n.name for n in nodes2] names.remove(n3.name) self.assertListEqual(names, names2) # Now, remove a node in the middle nodes.remove(n1) time.sleep(PROPAGATION_TIME) # wait for propagation self.assertEqual(len(nodes2), 2) names2 = [n.name for n in nodes2] names.remove(n1.name) print("After two removals: %s" % names2) self.assertListEqual(names, names2) # Check the order is still ok if I append a node again nodes.update(n1) time.sleep(PROPAGATION_TIME) # wait for propagation self.assertEqual(len(nodes2), 3) names2 = [n.name for n in nodes2] self.assertListEqual(names, names2[:2])
def _get_node_from_remote(self, id): nodeInCtxt = gRPC.NodeInContext(context=self._server_ctx, node=gRPC.Node(id=id)) gRPCNode = self._ctx.rpc.getNode(nodeInCtxt, _TIMEOUT_SECONDS) self._ids.append(id) self._nodes[id] = Node.deserialize(gRPCNode)
def test_accessing_nodes(self): world = self.ctx.worlds["base"] nodes = world.scene.nodes n1 = Node() n2 = Node() nodes.append(n1) nodes.append(n2) time.sleep(PROPAGATION_TIME) # wait for propagation self.assertEqual(n1, nodes[n1.id]) self.assertEqual(n2, nodes[n2.id]) with self.assertRaises(IndexError) as context: nodes["non-existing-id"] with self.assertRaises(IndexError) as context: nodes[len(nodes)]
def _update_node_from_remote(self, id): nodeInCtxt = gRPC.NodeInContext(context=self._server_ctx, node=gRPC.Node(id=id)) gRPCNode = self._ctx.rpc.getNode(nodeInCtxt, _TIMEOUT_SECONDS) updated_node = Node.deserialize(gRPCNode) self._nodes[id] = updated_node try: self._updated_ids.remove(id) except ValueError as ve: raise ve
def _get_node_from_remote(self, id): nodeInCtxt = gRPC.NodeInContext(context=self._server_ctx, node=gRPC.Node(id=id)) try: gRPCNode = self._ctx.rpc.getNode(nodeInCtxt, _TIMEOUT_SECONDS) except AbortionError as e: raise ValueError(e.details) # is it a new node, or rather an update to an existing one? if id not in self._ids: self._ids.append(id) self._nodes[id] = Node.deserialize(gRPCNode)
def test_base_parent(self): world = self.ctx.worlds["base"] nodes = world.scene.nodes parent = Node() child = Node() child.parent = parent.id nodes.append([parent, child]) time.sleep(PROPAGATION_TIME) # wait for propagation self.assertEqual(len(nodes), 3) # root node + our 2 nodes updated_child = nodes[child.id] updated_parent = nodes[parent.id] self.assertEqual(child.parent, updated_child.parent) self.assertEqual(parent.id, updated_parent.id) self.assertEqual(updated_child.parent, updated_parent.id) self.assertEqual(updated_parent.parent, world.scene.rootnode.id)
def test_default_parent(self): """ Checks that new node are parented to root node by default. """ world = self.ctx.worlds["base"] nodes = world.scene.nodes node = Node() self.assertIsNone(node.parent) nodes.append(node) time.sleep(PROPAGATION_TIME) # wait for propagation self.assertEqual(nodes[node.id].parent, world.scene.rootnode.id)
def _get_node_from_remote(self, id): assert (id is not None) nodeInCtxt = gRPC.NodeInContext(context=self._server_ctx, node=gRPC.Node(id=id)) try: gRPCNode = self._ctx.rpc.getNode(nodeInCtxt, _TIMEOUT_SECONDS) except AbortionError as e: raise IndexError(e.details) # is it a new node, or rather an update to an existing one? if id not in self._ids: self._ids.append(id) self._nodes[id] = Node.deserialize(gRPCNode)
def test_multiple_nodes(self): world = self.ctx.worlds["base"] nodes = world.scene.nodes self.assertEqual(len(nodes), 1) self.assertEqual(nodes[0].name, "root") new_nodes = [Node() for i in range(10)] nodes.append(new_nodes) time.sleep(PROPAGATION_TIME) # wait for propagation self.assertEqual(len(nodes), 11) nodes.remove(new_nodes) time.sleep(PROPAGATION_TIME) # wait for propagation self.assertEqual(len(nodes), 1)
def test_nodes(self): n = Node() self.assertIsNotNone(n.id) n.name = "test" n.type = MESH serialized = n.serialize(underworlds.underworlds_pb2.Node) n2 = Node.deserialize(serialized) self.assertEqual(n, n2)
except utils.NiteError as ne: logger.error("Unable to start the NiTE human tracker. Check " "the error messages in the console. Model data " "(s.dat, h.dat...) might be missing.") sys.exit(-1) logger.info("User tracker loaded.") logger.info("Now waiting for humans...") ############# with underworlds.Context("Human tracker") as ctx: world = ctx.worlds[args.world] nodes = world.scene.nodes camera = Node("kinect", ENTITY) translation_cam = transformations.translation_matrix((1, 0, 0.5)) # According to http://www.openni.ru/wp-content/uploads/2013/02/NITE-Algorithms.pdf # the sensor is oriented as follow: # " +X points to the right of the, +Y points up, and +Z # points in the direction of increasing depth." rotation_cam = transformations.euler_matrix(math.pi / 2, 0, math.pi / 2) camera.transformation = numpy.dot(translation_cam, rotation_cam) camera.parent = world.scene.rootnode.id nodes.append(camera) # Load the mannequin mesh into underworlds and get back the list of
def test_adding_nodes(self): world = self.ctx.worlds["base"] nodes = world.scene.nodes self.assertEqual(len(nodes), 1) self.assertEqual(nodes[0].name, "root") n = Node() n.name = "test" nodes.append(n) self.assertEqual( len(nodes), 1) # the effective length of nodes takes a few ms to be updated time.sleep(PROPAGATION_TIME) # wait for propagation self.assertEqual(len(nodes), 2) # Get another reference to the 'base' world, and check # our node is still here. world1bis = self.ctx.worlds["base"] nodes1bis = world1bis.scene.nodes self.assertTrue(world is world1bis) self.assertTrue(nodes is nodes1bis) # Get another reference to the 'base' world, via another context. # The 2 worlds are not the same python object anymore but # should remain consistent world2 = self.ctx2.worlds["base"] nodes2 = world2.scene.nodes self.assertFalse(world is world2) self.assertFalse(nodes is nodes2) self.assertEqual(len(nodes), 2) self.assertEqual(len(nodes2), 2) names = [n.name for n in nodes2] self.assertSetEqual(set(names), {"root", "test"}) # Add a second node and check it is available to all references n2 = Node() n2.name = "test2" nodes.update(n2) # 'update' and 'append' are actually aliases time.sleep(PROPAGATION_TIME) # wait for propagation self.assertEqual(len(nodes), 3) self.assertEqual(len(nodes2), 3) names2 = [n.name for n in nodes2] self.assertSetEqual(set(names2), {"root", "test", "test2"}) # ensure the ordering is maintained self.assertListEqual(names, names2[:2]) # Now alter 'world2' and make sure 'world' is updated accordingly n3 = Node() n3.name = "test3" nodes2.update(n3) time.sleep(PROPAGATION_TIME) # wait for propagation self.assertEqual(len(nodes), 4) names3 = [n.name for n in nodes] self.assertSetEqual(set(names3), {"root", "test", "test2", "test3"})
"the error messages in the console. Model data " "(s.dat, h.dat...) might be missing.") sys.exit(-1) logger.info("User tracker loaded.") logger.info("Now waiting for humans...") ############# with underworlds.Context("Human tracker") as ctx: world = ctx.worlds[args.world] nodes = world.scene.nodes camera = Node("kinect", ENTITY) translation_cam=transformations.translation_matrix((1,0,0.5)) # According to http://www.openni.ru/wp-content/uploads/2013/02/NITE-Algorithms.pdf # the sensor is oriented as follow: # " +X points to the right of the, +Y points up, and +Z # points in the direction of increasing depth." rotation_cam=transformations.euler_matrix(math.pi/2,0,math.pi/2) camera.transformation = numpy.dot(translation_cam, rotation_cam) camera.parent = world.scene.rootnode.id nodes.append(camera) # Load the mannequin mesh into underworlds and get back the list of # underworlds nodes
def test_adding_nodes(self): world = self.ctx.worlds["base"] nodes = world.scene.nodes self.assertEqual(len(nodes), 1) self.assertEqual(nodes[0].name, "root") n = Node() n.name = "test" nodes.append(n) self.assertEqual(len(nodes), 1) # the effective length of nodes takes a few ms to be updated time.sleep(PROPAGATION_TIME) # wait for propagation self.assertEqual(len(nodes), 2) # Get another reference to the 'base' world, and check # our node is still here. world1bis = self.ctx.worlds["base"] nodes1bis = world1bis.scene.nodes self.assertTrue(world is world1bis) self.assertTrue(nodes is nodes1bis) # Get another reference to the 'base' world, via another context. # The 2 worlds are not the same python object anymore but # should remain consistent world2 = self.ctx2.worlds["base"] nodes2 = world2.scene.nodes self.assertFalse(world is world2) self.assertFalse(nodes is nodes2) self.assertEqual(len(nodes), 2) self.assertEqual(len(nodes2), 2) names = [n.name for n in nodes2] self.assertSetEqual(set(names), {"root", "test"}) # Add a second node and check it is available to all references n2 = Node() n2.name = "test2" nodes.update(n2) # 'update' and 'append' are actually aliases time.sleep(PROPAGATION_TIME) # wait for propagation self.assertEqual(len(nodes), 3) self.assertEqual(len(nodes2), 3) names2 = [n.name for n in nodes2] self.assertSetEqual(set(names2), {"root", "test", "test2"}) # ensure the ordering is maintained self.assertListEqual(names, names2[:2]) # Now alter 'world2' and make sure 'world' is updated accordingly n3 = Node() n3.name = "test3" nodes2.update(n3) time.sleep(PROPAGATION_TIME) # wait for propagation self.assertEqual(len(nodes), 4) names3 = [n.name for n in nodes] self.assertSetEqual(set(names3), {"root", "test", "test2", "test3"})
def test_topology(self): topo = self.observer_ctx.topology() self.assertEquals(len(topo.clients), 1) self.assertIn(self.observer_ctx.id, [c.id for c in topo.clients]) self.assertEquals(len(topo.worlds), 0) self.observer_ctx.worlds["base"] topo = self.observer_ctx.topology() self.assertEquals(len(topo.worlds), 1) self.assertIn("base", topo.worlds) # Add a PROVIDER client provider_id = None provider_ctx = underworlds.Context("provider") world = provider_ctx.worlds["base"] world.scene.nodes.append(Node()) # create and add a random node provider_id = provider_ctx.id topo = self.observer_ctx.topology() self.assertEquals(len(topo.clients), 2) self.assertIn(provider_id, [c.id for c in topo.clients]) provider = {c.id:c for c in topo.clients}[provider_id] self.assertIn("base", [l.world for l in provider.links]) link = {l.world:l for l in provider.links}["base"] self.assertEquals(PROVIDER, link.type) last_provider_activity = link.last_activity.time # Add a READER client reader_id = None with underworlds.Context("reader") as reader_ctx: world2 = reader_ctx.worlds["base"] for n in world2.scene.nodes: print(n) reader_id = reader_ctx.id topo = self.observer_ctx.topology() self.assertEquals(len(topo.clients), 3) self.assertIn(reader_id, [c.id for c in topo.clients]) reader = {c.id:c for c in topo.clients}[reader_id] self.assertIn("base", [l.world for l in reader.links]) link2 = {l.world:l for l in reader.links}["base"] self.assertEquals(READER, link2.type) # Check the provider is still here provider = {c.id:c for c in topo.clients}[provider_id] self.assertIn("base", [l.world for l in provider.links]) link = {l.world:l for l in provider.links}["base"] self.assertEquals(PROVIDER, link.type) # The provider has not been used: the last activity timestamp should be the same self.assertEquals(last_provider_activity, link.last_activity.time) # Modify the world from the PROVIDER context time.sleep(0.2) world.scene.nodes.append(Node()) # create and add a random node topo = self.observer_ctx.topology() # Check the provider is still here provider = {c.id:c for c in topo.clients}[provider_id] self.assertIn("base", [l.world for l in provider.links]) link = {l.world:l for l in provider.links}["base"] self.assertEquals(PROVIDER, link.type) # The provider *has been used*: the last activity timestamp should be higher self.assertLess(last_provider_activity, link.last_activity.time) provider_ctx.close() # the provider is not here anymore... topo = self.observer_ctx.topology() self.assertEquals(len(topo.clients), 2) # the reader is not here anymore... topo = self.observer_ctx.topology() self.assertEquals(len(topo.clients), 1)
#! /usr/bin/env python import time import logging logger = logging.getLogger("underworlds.testing") logging.basicConfig(level=logging.DEBUG) import underworlds from underworlds.types import Node # Add a PROVIDER client with underworlds.Context("provider") as provider_ctx: world = provider_ctx.worlds["base"] world.scene.nodes.update(Node()) # create and add a random node # Add a READER client with underworlds.Context("reader") as reader_ctx: world = reader_ctx.worlds["base"] world2 = reader_ctx.worlds["brave new world"] for n in world.scene.nodes: world2.scene.nodes.update(n)