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 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_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)
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_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"})