def test_updateFragments_partial(self): """ Simliar to previous test in the sense that it spawns and updates fragments. However, this time some fragments will be removed altogether, instead of just being updated. """ dibbler = self.dibbler # The original template has the following three fragments: frags_orig = { 'f1': getFragRaw(), 'f2': getFragDae(), 'f3': getFragRaw() } t1 = getTemplate('t1', fragments=frags_orig) # The fragment update will use the following data. It translates to # keeping the first intact, removing the second, and modifying the # fragment type for the third one. frags_new = { 'f2': getFragNone(), 'f3': getFragDae(), } # Add the template, spawn one instance, and verify all fragments. assert dibbler.addTemplate(t1).ok ret = dibbler.spawnTemplate(1, t1.aid) assert ret.ok self.verifyRaw(ret.data['url_frag'], 'f1', frags_orig) self.verifyDae(ret.data['url_frag'], 'f2', frags_orig) self.verifyRaw(ret.data['url_frag'], 'f3', frags_orig) # Record the current number of files in Dibbler. There must be one # 'meta.json', two raw files (one each), 3 Collada files (dae + 2 # textures). These files exist twice, once in the template store and # once in the instance store. file_cnt = dibbler.getNumFiles().data assert file_cnt == 2 * (1 + 2 * 1 + 1 * 3) # Update the fragments: keep first (raw, +0), delete second (dae, -3), # convert third from raw to dae (-1 + 3). assert dibbler.updateFragments(1, frags_new).ok # Record the current number of files in Dibbler. assert dibbler.getNumFiles().data == file_cnt + (0) + (-3) + (-1 + 3) # Verify that the first fragment is still intact, the second does not # exist anymore, and the third was updated. self.verifyRaw(ret.data['url_frag'], 'f1', frags_orig) with pytest.raises(AssertionError): self.verifyDae(ret.data['url_frag'], 'f2', frags_orig) self.verifyDae(ret.data['url_frag'], 'f3', frags_new)
def test_Template(self): # Define boosters and factories. boosters = { "0": Booster(pos=(0, 1, 2), direction=(1, 0, 0), minval=0, maxval=1, force=0), "1": Booster(pos=(3, 4, 5), direction=(0, 1, 0), minval=0, maxval=2, force=0), } factories = { "0": Factory(pos=(0, 1, 2), direction=(0, 0, 1), templateID="_templateBox", exit_speed=(0, 1)), "1": Factory(pos=(3, 4, 5), direction=(0, 1, 0), templateID="_templateBox", exit_speed=(0, 1)), } rbs = getRigidBody(position=(1, 2, 3)) # Define a new template with two boosters and add it to Azrael. temp_t = getTemplate( "t1", rbs=rbs, fragments={"1": getFragRaw(), "2": getFragDae()}, boosters=boosters, factories=factories ) # Verify that it is JSON compatible. assert self.isJsonCompatible(temp_t, Template) # Verify that Template._asdict() method calls the _asdict() methods # for all collision shapes, fragments, boosters, and factories. temp_d = temp_t._asdict() fragments_d = {k: v._asdict() for (k, v) in temp_t.fragments.items()} boosters_d = {k: v._asdict() for (k, v) in temp_t.boosters.items()} factories_d = {k: v._asdict() for (k, v) in temp_t.factories.items()} rbs_d = rbs._asdict() assert temp_d["fragments"] == fragments_d assert temp_d["boosters"] == boosters_d assert temp_d["factories"] == factories_d assert temp_d["rbs"] == rbs_d
def getTestTemplate(self, templateID='templateID'): """ Return a valid template with non-trivial data. The template contains multiple fragments (Raw and Collada), boosters, factories, and a rigid body. This is a convenience method only. """ # Define a new object with two boosters and one factory unit. # The 'boosters' and 'factories' arguments are a list of named # tuples. Their first argument is the unit ID (Azrael does not # automatically assign any IDs). boosters = { '0': aztypes.Booster(position=(0, 1, 2), direction=(0, 0, 1), force=0), '1': aztypes.Booster(position=(6, 7, 8), direction=(0, 1, 0), force=0), } factories = { '0': aztypes.Factory(position=(0, 0, 0), direction=(0, 0, 1), templateID='_templateBox', exit_speed=(0.1, 0.5)) } # Create some fragments... frags = {'f1': getFragRaw(), 'f2': getFragDae()} # ... and a body... body = getRigidBody(position=(1, 2, 3)) # ... then compile and return the template. return azrael.test.test.getTemplate( templateID, rbs=body, fragments=frags, boosters=boosters, factories=factories)
def test_deleteInstance(self): """ Add/remove an instance from Dibbler via Clerk and verify via WebServer. """ self.dibbler.reset() azrael.datastore.init(flush=True) clerk = azrael.clerk.Clerk() # Create a Template. frags = {'name1': getFragRaw()} t1 = getTemplate('t1', fragments=frags) # Add-, spawn-, and verify the template. assert clerk.addTemplates([t1]).ok self.verifyTemplate('{}/t1'.format(config.url_templates), t1.fragments) ret = clerk.spawn([{'templateID': 't1', 'rbs': {'imass': 1}}]) assert ret.data == ['1'] # Verify that the instance exists. url_inst = config.url_instances self.verifyTemplate('{}/{}'.format(url_inst, 1), frags) # Delete the instance and verify it is now gone. cnt = self.dibbler.getNumFiles().data assert clerk.removeObjects(['1']) == (True, None, None) self.dibbler.getNumFiles().data == cnt - 2 with pytest.raises(AssertionError): self.verifyTemplate('{}/{}'.format(url_inst, 1), frags)
def test_Template(self): # Define boosters and factories. boosters = { '0': Booster(position=(0, 1, 2), direction=(1, 0, 0), force=0), '1': Booster(position=(3, 4, 5), direction=(0, 1, 0), force=0) } factories = { '0': Factory(position=(0, 1, 2), direction=(0, 0, 1), templateID='_templateBox', exit_speed=(0, 1)), '1': Factory(position=(3, 4, 5), direction=(0, 1, 0), templateID='_templateBox', exit_speed=(0, 1)) } rbs = getRigidBody(position=(1, 2, 3)) # Define a new template with two boosters and add it to Azrael. frags = {'1': getFragRaw(), '2': getFragDae()} temp_t = getTemplate('t1', rbs=rbs, fragments=frags, boosters=boosters, factories=factories) # Verify that Template._asdict() method calls the _asdict() methods # for all collision shapes, fragments, boosters, and factories. temp_d = temp_t._asdict() fragments_d = {k: v._asdict() for (k, v) in temp_t.fragments.items()} boosters_d = {k: v._asdict() for (k, v) in temp_t.boosters.items()} factories_d = {k: v._asdict() for (k, v)in temp_t.factories.items()} rbs_d = rbs._asdict() assert temp_d['fragments'] == fragments_d assert temp_d['boosters'] == boosters_d assert temp_d['factories'] == factories_d assert temp_d['rbs'] == rbs_d
def test_remove_fragments(self, client_type): """ Remove a fragment. This test is basically the integration test for 'test_dibbler.test_updateFragments_partial'. """ # Get the client for this test. client = self.clients[client_type] # Convenience. objID = 1 # The original template has the following three fragments: frags_orig = { 'fname_1': getFragRaw(), 'fname_2': getFragDae(), 'fname_3': getFragRaw(), } t1 = getTemplate('t1', fragments=frags_orig) # Add a new template and spawn it. assert client.addTemplates([t1]).ok new_obj = {'templateID': t1.aid, 'rbs': {'position': (1, 1, 1), 'velocityLin': (-1, -1, -1)}} assert client.spawn([new_obj]) == (True, None, [objID]) # Query the fragment geometries and Body State to verify that both # report three fragments. ret = client.getFragments([objID]) assert ret.ok and len(ret.data[objID]) == 3 ret = client.getObjectStates(objID) assert ret.ok and len(ret.data[objID]['frag']) == 3 # Update the fragments as follows: keep the first intact, remove the # second, and modify the third one. frags_new = { 'fname_2': getFragNone()._asdict(), 'fname_3': getFragDae()._asdict() } assert client.setFragments({objID: frags_new}).ok # After the last update there must now only be two fragments. ret = client.getFragments([objID]) assert ret.ok and len(ret.data[objID]) == 2 ret = client.getObjectStates(objID) assert ret.ok and len(ret.data[objID]['frag']) == 2
def test_spawnTemplates(self): """ Spawn a template and verify it is available via WebServer. """ self.dibbler.reset() azrael.datastore.init(flush=True) clerk = azrael.clerk.Clerk() # # Create two Templates. The first has only one Raw- and two # # Collada geometries, the other has it the other way around. frags_t1 = {'raw1': getFragRaw(), 'dae2': getFragDae(), 'dae3': getFragDae()} frags_t2 = {'raw4': getFragRaw(), 'raw5': getFragRaw(), 'dae6': getFragDae()} body_t1 = getRigidBody(cshapes={'cssphere': getCSSphere()}) body_t2 = getRigidBody(cshapes={'csbox': getCSBox()}) t1 = getTemplate('t1', rbs=body_t1, fragments=frags_t1) t2 = getTemplate('t2', rbs=body_t2, fragments=frags_t2) del frags_t1, frags_t2 # Add both templates and verify they are available. assert clerk.addTemplates([t1, t2]).ok self.verifyTemplate('{}/t1'.format(config.url_templates), t1.fragments) self.verifyTemplate('{}/t2'.format(config.url_templates), t2.fragments) # No object instance with ID=1 must exist yet. url_inst = config.url_instances with pytest.raises(AssertionError): self.verifyTemplate('{}/{}'.format(url_inst, 1), t1.fragments) # Spawn the first template (it must get objID=1). ret = clerk.spawn([{'templateID': 't1', 'rbs': {'imass': 1}}]) assert ret.data == ['1'] self.verifyTemplate('{}/{}'.format(url_inst, 1), t1.fragments) # Spawn two more templates and very their instance models. new_objs = [{'templateID': 't2', 'rbs': {'imass': 1}}, {'templateID': 't1', 'rbs': {'imass': 1}}] ret = clerk.spawn(new_objs) assert ret.data == ['2', '3'] self.verifyTemplate('{}/{}'.format(url_inst, 2), t2.fragments) self.verifyTemplate('{}/{}'.format(url_inst, 3), t1.fragments)
def test_setFragments_dae(self, client_type): """ Spawn a new object and modify its geometry at runtime. """ # Get the client for this test. client = self.clients[client_type] # Get a Collada fragment. f_dae = {'f_dae': getFragDae()} # Add a new template and spawn it. temp = getTemplate('t1', fragments=f_dae) assert client.addTemplates([temp]).ok new_obj = {'templateID': temp.aid, 'rbs': {'position': (1, 1, 1), 'velocityLin': (-1, -1, -1)}} ret = client.spawn([new_obj]) objID = ret.data[0] assert ret.ok and ret.data == [objID] del temp, new_obj, ret # Query the body states to obtain the 'version' value. ret = client.getRigidBodies(objID) assert ret.ok version = ret.data[objID]['rbs'].version # Fetch-, modify-, update- and verify the geometry. ret = client.getFragments([objID]) assert ret.ok assert ret.data[objID]['f_dae']['fragtype'] == 'DAE' # Change the geometry for fragment 'f_dae' to a RAW type. assert client.setFragments({objID: {'f_dae': getFragRaw()._asdict()}}).ok # Ensure the fragment is now indeed of type 'RAW'. ret = client.getFragments([objID]) assert ret.ok assert ret.data[objID]['f_dae']['fragtype'] == 'RAW' # Ensure 'version' is different as well. ret = client.getRigidBodies(objID) assert ret.ok and (ret.data[objID]['rbs'].version != version) # Change the fragment geometry once more. version = ret.data[objID]['rbs'].version assert client.setFragments({objID: {'f_dae': getFragDae()._asdict()}}).ok # Ensure it now has type 'DAE' again. ret = client.getFragments([objID]) assert ret.ok assert ret.data[objID]['f_dae']['fragtype'] == 'DAE' # Ensure 'version' is different as well. ret = client.getRigidBodies(objID) assert ret.ok and (ret.data[objID]['rbs'].version != version)
def test_updateFragments(self): """ Modify the fragments of a spawned object. """ self.dibbler.reset() azrael.database.init() clerk = azrael.clerk.Clerk() # Create two Templates. The first has only one Raw- and two # Collada geometries, the other has it the other way around. frags_old = {'name1': getFragRaw(), 'name2': getFragDae(), 'name3': getFragDae()} frags_new = {'name1': getFragDae(), 'name2': getFragDae(), 'name3': getFragRaw()} t1 = getTemplate('t1', fragments=frags_old) # Add-, spawn-, and verify the template. assert clerk.addTemplates([t1]).ok self.verifyTemplate('{}/t1'.format(config.url_templates), t1.fragments) ret = clerk.spawn([{'templateID': 't1', 'rbs': {'imass': 1}}]) objID = 1 assert ret.data == (objID, ) # Verify that the instance has the old fragments, not the new ones. url_inst = config.url_instances self.verifyTemplate('{}/{}'.format(url_inst, 1), frags_old) with pytest.raises(AssertionError): self.verifyTemplate('{}/{}'.format(url_inst, 1), frags_new) # Update the fragments. tmp = {k: v._asdict() for (k, v) in frags_new.items()} clerk.setFragments({objID: tmp}) # Verify that the instance now has the new fragments, but not the old # ones anymore. self.verifyTemplate('{}/{}'.format(url_inst, 1), frags_new) with pytest.raises(AssertionError): self.verifyTemplate('{}/{}'.format(url_inst, 1), frags_old)
def test_updateFragments_all(self): """ Spawn a template and update all its fragments. """ dibbler = self.dibbler # The original template has two fragments, and we will update one of # them. frags_orig = {'o1': getFragRaw(), 'o2': getFragDae()} frags_new = {'o1': getFragDae()} t1 = getTemplate('t1', fragments=frags_orig) # Add the template and spawn two instances. assert dibbler.addTemplate(t1).ok ret_11 = dibbler.spawnTemplate(11, t1.aid) ret_2 = dibbler.spawnTemplate(2, t1.aid) assert ret_11.ok and ret_2.ok self.verifyRaw(ret_11.data['url_frag'], 'o1', frags_orig) self.verifyDae(ret_11.data['url_frag'], 'o2', frags_orig) self.verifyRaw(ret_2.data['url_frag'], 'o1', frags_orig) self.verifyDae(ret_2.data['url_frag'], 'o2', frags_orig) # Attempt to change the fragment of a non-existing object. assert not dibbler.updateFragments(20, frags_new).ok # Attempt to change the fragment of another non-existing object, but # the object ID of this one is '1', which means it is available at # '/somewhere/1/...'. However, an object at '/somewhere/11/...' already # exists, and without the trailing '/' the first would be a sub-string # of the latter. The update method must therefore take care to properly # test for existence, especially since directories, internally, do not # have a trailing '/'. assert not dibbler.updateFragments(1, frags_new).ok # The previous attempts to modify fragments of non-existing objectst # must not have modified the fragments. self.verifyRaw(ret_11.data['url_frag'], 'o1', frags_orig) self.verifyDae(ret_11.data['url_frag'], 'o2', frags_orig) self.verifyRaw(ret_2.data['url_frag'], 'o1', frags_orig) self.verifyDae(ret_2.data['url_frag'], 'o2', frags_orig) # Change the first fragments of the first object. assert dibbler.updateFragments(11, frags_new).ok # Verify that only the first fragment of the '11' object has changed. self.verifyDae(ret_11.data['url_frag'], 'o1', frags_new) self.verifyDae(ret_11.data['url_frag'], 'o2', frags_orig) self.verifyRaw(ret_2.data['url_frag'], 'o1', frags_orig) self.verifyDae(ret_2.data['url_frag'], 'o2', frags_orig)
def test_addTemplates(self): """ Add and query a template with one Raw fragment. """ self.dibbler.reset() azrael.datastore.init(flush=True) clerk = azrael.clerk.Clerk() # Create two Templates. The first has only one Raw- and two # Collada geometries, the other has it the other way around. frags_t1 = {'foo1': getFragRaw(), 'bar2': getFragDae(), 'bar3': getFragDae()} frags_t2 = {'foo4': getFragRaw(), 'foo5': getFragRaw(), 'bar6': getFragDae()} body_a = getRigidBody(cshapes={'cssphere': getCSSphere()}) body_b = getRigidBody(cshapes={'csbox': getCSBox()}) t1 = getTemplate('t1', rbs=body_a, fragments=frags_t1) t2 = getTemplate('t2', rbs=body_b, fragments=frags_t2) del frags_t1, frags_t2 # Add the first template. assert clerk.addTemplates([t1]) == (True, None, {'t1': True}) # Attempt to add the same template a second time. This must not do # anything. assert clerk.addTemplates([t1]) == (True, None, {'t1': False}) # Verify the first template is available for download via WebServer. url_template = config.url_templates self.verifyTemplate('{}/t1'.format(url_template), t1.fragments) # Add the second template and verify both are available for download # via WebServer. assert clerk.addTemplates([t2]).ok self.verifyTemplate('{}/t1'.format(url_template), t1.fragments) self.verifyTemplate('{}/t2'.format(url_template), t2.fragments)
def test_FragMeta(self): for Getter in (getFragRaw, getFragDae, getFragNone): # Get a proper FragMeta, and a stunted one where the 'fragdata' # field is None. This case often happens internally in Azrael # because the meta data is stored in a separate database. frag_a = Getter() frag_b = frag_a._replace(fragdata=None) assert self.isJsonCompatible(frag_a, FragMeta) assert self.isJsonCompatible(frag_b, FragMeta) # Verify that 'FragMeta._asdict' also converts the 'fragdata' field # to dictionaries. frag_t = getFragRaw() frag_d = frag_t._asdict() assert isinstance(frag_d, dict) tmp = frag_t.fragdata._asdict() assert isinstance(tmp, dict) assert tmp == frag_d["fragdata"]
def setup_method(self, method): # Reset the database. azrael.database.init() # Flush the model database. self.dibbler.reset() # Insert default objects. None of them has an actual geometry but # their collision shapes are: none, sphere, box. clerk = azrael.clerk.Clerk() frag = {'NoName': getFragRaw()} rbs_empty = getRigidBody(cshapes={'csempty': getCSEmpty()}) rbs_sphere = getRigidBody(cshapes={'cssphere': getCSSphere()}) rbs_box = getRigidBody(cshapes={'csbox': getCSBox()}) t1 = getTemplate('_templateEmpty', rbs=rbs_empty, fragments=frag) t2 = getTemplate('_templateSphere', rbs=rbs_sphere, fragments=frag) t3 = getTemplate('_templateBox', rbs=rbs_box, fragments=frag) ret = clerk.addTemplates([t1, t2, t3]) assert ret.ok
def test_addRawTemplate(self): """ Add a raw template and fetch the individual files again afterwards. """ # Create a Dibbler instance and flush all data. dibbler = self.dibbler assert dibbler.getNumFiles() == (True, None, 0) # Define a template for this test. frags = {'foo': getFragRaw()} t_raw = getTemplate('_templateEmpty', fragments=frags) # Add the first template and verify that the database now contains # exactly two files (a meta file, and the actual fragment data). ret = dibbler.addTemplate(t_raw) assert ret.ok assert dibbler.getNumFiles() == (True, None, 2) # Fetch- and verify the model. self.verifyRaw(ret.data['url_frag'], 'foo', frags)
def test_Template(self): # Define boosters and factories. boosters = { '0': Booster(position=(0, 1, 2), direction=(1, 0, 0), force=0), '1': Booster(position=(3, 4, 5), direction=(0, 1, 0), force=0) } factories = { '0': Factory(position=(0, 1, 2), direction=(0, 0, 1), templateID='_templateBox', exit_speed=(0, 1)), '1': Factory(position=(3, 4, 5), direction=(0, 1, 0), templateID='_templateBox', exit_speed=(0, 1)) } rbs = getRigidBody(position=(1, 2, 3)) # Define a new template with two boosters and add it to Azrael. frags = {'1': getFragRaw(), '2': getFragDae()} temp_t = getTemplate('t1', rbs=rbs, fragments=frags, boosters=boosters, factories=factories) # Verify that Template._asdict() method calls the _asdict() methods # for all collision shapes, fragments, boosters, and factories. temp_d = temp_t._asdict() fragments_d = {k: v._asdict() for (k, v) in temp_t.fragments.items()} boosters_d = {k: v._asdict() for (k, v) in temp_t.boosters.items()} factories_d = {k: v._asdict() for (k, v) in temp_t.factories.items()} rbs_d = rbs._asdict() assert temp_d['fragments'] == fragments_d assert temp_d['boosters'] == boosters_d assert temp_d['factories'] == factories_d assert temp_d['rbs'] == rbs_d
def test_spawnTemplate(self): """ Add two templates, then spawn the first one twice and the second one once. """ dibbler = self.dibbler # Define two templates. frag_raw = {'fraw': getFragRaw()} frag_dae = {'fdae': getFragDae()} t_raw = getTemplate('t_name_raw', fragments=frag_raw) t_dae = getTemplate('t_name_dae', fragments=frag_dae) # Add the templates and verify there are 6 files in the DB now. The # first template has two files (1 meta.json plus 1 for the raw data) # and the second has 4 files (1 meta.json plus 3 for the Collada data). dibbler.addTemplate(t_raw) dibbler.addTemplate(t_dae) assert dibbler.getNumFiles() == (True, None, 2 + 4) # Spawn some instances. ret_1 = dibbler.spawnTemplate(1, t_raw.aid) ret_2 = dibbler.spawnTemplate(2, t_raw.aid) ret_3 = dibbler.spawnTemplate(3, t_dae.aid) assert ret_1.ok and ret_2.ok and ret_3.ok # Dibbler must now hold the original 6 files plus an additional 8 files # (2x2 for the two Raw instances, and another 4 for the one Collada # instance). assert dibbler.getNumFiles() == (True, None, (2 + 4) + (2 * 2 + 1 * 4)) # Verify that all files are correct. self.verifyRaw(ret_1.data['url_frag'], 'fraw', frag_raw) self.verifyRaw(ret_2.data['url_frag'], 'fraw', frag_raw) self.verifyDae(ret_3.data['url_frag'], 'fdae', frag_dae) # Attempt to spawn a non-existing template. This must fail and the # number of files in Dibbler must not change. assert not dibbler.spawnTemplate(10, 'blah').ok assert dibbler.getNumFiles() == (True, None, (2 + 4) + (2 * 2 + 1 * 4))
def test_update_FragmentStates(self, client_type): """ Query and modify fragment states. Note that fragment states are updated via 'setFragments'. """ # Get the client for this test. client = self.clients[client_type] # Convenience. objID = 1 # Add a new template and spawn it. temp = getTemplate('t1', fragments={'bar': getFragRaw()}) assert client.addTemplates([temp]).ok new_obj = {'templateID': temp.aid, 'rbs': {'position': (1, 1, 1), 'velocityLin': (-1, -1, -1)}} ret = client.spawn([new_obj]) assert ret.ok and ret.data == [objID] del temp, new_obj, ret # Query the Body State to get the Fragment States. Then verify the # Fragment State named 'bar'. ret = client.getObjectStates(objID) ref = {'bar': {'scale': 1, 'position': [0, 0, 0], 'rotation': [0, 0, 0, 1]}} assert ret.ok assert ret.data[objID]['frag'] == ref # Modify and update the fragment states in Azrael, then query and # verify it worked. newStates = {objID: {'bar': {'scale': 2.2, 'position': [1, 2, 3], 'rotation': [1, 0, 0, 0]}}} assert client.setFragments(newStates).ok ret = client.getObjectStates(objID) assert ret.ok ret = ret.data[objID]['frag']['bar'] assert ret == newStates[objID]['bar']
def test_create_fetch_template(self, client_type): """ Add a new object to the templateID DB and query it again. """ # Get the client for this test. client = self.clients[client_type] # Request an invalid ID. assert not client.getTemplates(['blah']).ok # Clerk has default objects. This one has an empty collision shape... name_1 = '_templateEmpty' ret = client.getTemplates([name_1]) assert ret.ok and (len(ret.data) == 1) assert ret.data[name_1]['template'].rbs.cshapes == {'csempty': getCSEmpty()} # ... this one is a sphere... name_2 = '_templateSphere' ret = client.getTemplates([name_2]) assert ret.ok and (len(ret.data) == 1) assert ret.data[name_2]['template'].rbs.cshapes == {'cssphere': getCSSphere()} # ... and this one is a box. name_3 = '_templateBox' ret = client.getTemplates([name_3]) assert ret.ok and (len(ret.data) == 1) assert ret.data[name_3]['template'].rbs.cshapes == {'csbox': getCSBox()} # Retrieve all three again but with a single call. ret = client.getTemplates([name_1, name_2, name_3]) assert ret.ok assert set(ret.data.keys()) == set((name_1, name_2, name_3)) assert ret.data[name_2]['template'].rbs.cshapes == {'cssphere': getCSSphere()} assert ret.data[name_3]['template'].rbs.cshapes == {'csbox': getCSBox()} assert ret.data[name_1]['template'].rbs.cshapes == {'csempty': getCSEmpty()} # Add a new object template. frag = {'bar': getFragRaw()} body = getRigidBody() temp_name = 't1' temp_orig = getTemplate(temp_name, rbs=body, fragments=frag) assert client.addTemplates([temp_orig]).ok # Fetch the just added template again and verify its content (skip the # geometry because it contains only meta information and will be # checked afterwards). ret = client.getTemplates([temp_name]) assert ret.ok and (len(ret.data) == 1) temp_out = ret.data[temp_name]['template'] assert temp_out.boosters == temp_orig.boosters assert temp_out.factories == temp_orig.factories assert temp_out.rbs == temp_orig.rbs # Fetch the geometry from the web server and verify it. ret = client.getTemplateGeometry(ret.data[temp_name]) assert ret.ok assert ret.data['bar'] == frag['bar'].fragdata del ret, temp_out, temp_orig # Define a new object with two boosters and one factory unit. # The 'boosters' and 'factories' arguments are a list of named # tuples. Their first argument is the unit ID (Azrael does not # automatically assign any). boosters = { '0': types.Booster(pos=(0, 0, 0), direction=(0, 0, 1), minval=0, maxval=0.5, force=0), '1': types.Booster(pos=(0, 0, 0), direction=(0, 0, 1), minval=0, maxval=0.5, force=0), } factories = { '0': types.Factory(pos=(0, 0, 0), direction=(0, 0, 1), templateID='_templateBox', exit_speed=(0.1, 0.5)) } # Attempt to query the geometry of a non-existing object. assert client.getFragments([1]) == (True, None, {1: None}) # Define a new template, add it to Azrael, spawn it, and record its # object ID. body = getRigidBody(cshapes={'csbox': getCSBox()}) temp = getTemplate('t2', rbs=body, fragments=frag, boosters=boosters, factories=factories) assert client.addTemplates([temp]).ok init = {'templateID': temp.aid, 'rbs': {'position': (0, 0, 0)}} ret = client.spawn([init]) assert ret.ok and len(ret.data) == 1 objID = ret.data[0] # Retrieve- and verify the geometry of the just spawned object. ret = client.getFragments([objID]) assert ret.ok assert ret.data[objID]['bar']['fragtype'] == 'RAW' # Retrieve the entire template and verify the CS and geometry, and # number of boosters/factories. ret = client.getTemplates([temp.aid]) assert ret.ok and (len(ret.data) == 1) t_data = ret.data[temp.aid]['template'] assert t_data.rbs == body assert t_data.boosters == temp.boosters assert t_data.factories == temp.factories # Fetch the geometry from the Web server and verify it is correct. ret = client.getTemplateGeometry(ret.data[temp.aid]) assert ret.ok assert ret.data['bar'] == frag['bar'].fragdata
def test_FragMeta(self): # Verify that 'FragMeta._asdict' convert to a dictionary. frag_t = getFragRaw() frag_d = frag_t._asdict() assert isinstance(frag_d, dict)
def test_deleteInstance(self): """ Add and remove an instance. """ dibbler = self.dibbler # Define two templates. frag_raw = {'foo': getFragRaw()} frag_dae = {'bar': getFragDae()} t_raw = getTemplate('temp_raw', fragments=frag_raw) t_dae = getTemplate('temp_dae', fragments=frag_dae) # Verify that Dibbler is empty. assert dibbler.getNumFiles() == (True, None, 0) # Add- and verify a Raw- and Collada template. The raw template 2 files # (meta.json plus model.json) whereas the Collada template has 4 files # (meta.json plus 1 dae file plus 2 textures). ret = dibbler.addTemplate(t_raw) assert dibbler.getNumFiles() == (True, None, 2) self.verifyRaw(ret.data['url_frag'], 'foo', frag_raw) ret = dibbler.addTemplate(t_dae) assert dibbler.getNumFiles() == (True, None, 2 + 4) self.verifyDae(ret.data['url_frag'], 'bar', frag_dae) # Spawn some instances. assert dibbler.spawnTemplate(1, 'temp_raw').ok assert dibbler.spawnTemplate(2, 'temp_dae').ok assert dibbler.spawnTemplate(3, 'temp_raw').ok self.verifyRaw('{}/1'.format(config.url_instances), 'foo', frag_raw) self.verifyDae('{}/2'.format(config.url_instances), 'bar', frag_dae) self.verifyRaw('{}/3'.format(config.url_instances), 'foo', frag_raw) base_cnt = (2 + 4) + 2 * 2 + 1 * 4 assert dibbler.getNumFiles() == (True, None, base_cnt) # Remove a non-existing object. This must succeed but Dibbler must not # have removed any files. assert dibbler.deleteInstance(10) == (True, None, 0) assert dibbler.getNumFiles() == (True, None, base_cnt) # Remove the first Raw object. This must remove two files and leave the # other two instances intact. assert dibbler.deleteInstance(1) == (True, None, 2) base_cnt -= 2 assert dibbler.getNumFiles() == (True, None, base_cnt) with pytest.raises(AssertionError): self.verifyRaw('{}/1'.format(config.url_instances), 'foo', frag_raw) self.verifyDae('{}/2'.format(config.url_instances), 'bar', frag_dae) self.verifyRaw('{}/3'.format(config.url_instances), 'foo', frag_raw) # Remove the same instance again. This must succeed but Dibbler must # not remove any files. assert dibbler.deleteInstance(1) == (True, None, 0) # Remove the Collada instance. This must delete four files (meta.json + # dae + 2 textures). assert dibbler.deleteInstance(2) == (True, None, 4) base_cnt -= 4 assert dibbler.getNumFiles() == (True, None, base_cnt) with pytest.raises(AssertionError): self.verifyRaw('{}/1'.format(config.url_instances), 'foo', frag_raw) with pytest.raises(AssertionError): self.verifyDae('{}/2'.format(config.url_instances), 'bar', frag_dae) self.verifyRaw('{}/3'.format(config.url_instances), 'foo', frag_raw) # Remove the second Raw instance. assert dibbler.deleteInstance(3) == (True, None, 2) base_cnt -= 2 assert dibbler.getNumFiles() == (True, None, base_cnt) with pytest.raises(AssertionError): self.verifyRaw('{}/1'.format(config.url_instances), 'foo', frag_raw) with pytest.raises(AssertionError): self.verifyDae('{}/2'.format(config.url_instances), 'bar', frag_dae) with pytest.raises(AssertionError): self.verifyRaw('{}/3'.format(config.url_instances), 'foo', frag_raw)
def test_deleteTemplate(self): """ Add two templates and then delete them. This functions also tests some corner cases where the delete-request is a substring of another template. """ dibbler = self.dibbler # Define two templates. frag_raw = {'foo': getFragRaw()} frag_dae = {'bar': getFragDae()} t1 = getTemplate('name1', fragments=frag_dae) t11 = getTemplate('name11', fragments=frag_raw) # Verify that Dibbler's database is pristine. assert dibbler.getNumFiles() == (True, None, 0) # Add- and verify the Raw template. ret = dibbler.addTemplate(t11) assert dibbler.getNumFiles() == (True, None, 2) self.verifyRaw(ret.data['url_frag'], 'foo', frag_raw) # Remove the Raw template and ensure it does not exist anymore. assert dibbler.deleteTemplate('name11').ok assert dibbler.getNumFiles() == (True, None, 0) with pytest.raises(AssertionError): self.verifyRaw(ret.data['url_frag'], 'foo', frag_raw) # Attempt to remove the Raw template once more. Dibbler must not delete # any files, albeit the call itself must succeed. assert dibbler.deleteTemplate('blah').ok assert dibbler.getNumFiles() == (True, None, 0) # Add- and verify the Raw- and Collada templates. del ret ret_raw = dibbler.addTemplate(t11) ret_dae = dibbler.addTemplate(t1) assert dibbler.getNumFiles() == (True, None, 6) self.verifyRaw(ret_raw.data['url_frag'], 'foo', frag_raw) self.verifyDae(ret_dae.data['url_frag'], 'bar', frag_dae) # Remove the Collada template whose name is a substring of the first. assert dibbler.deleteTemplate('name1') == (True, None, 4) assert dibbler.getNumFiles() == (True, None, 2) self.verifyRaw(ret_raw.data['url_frag'], 'foo', frag_raw) with pytest.raises(AssertionError): self.verifyRaw(ret_dae.data['url_frag'], 'bar', frag_dae) # Remove the Collada template again. No files must be deleted this # time. assert dibbler.deleteTemplate('name1') == (True, None, 0) assert dibbler.getNumFiles() == (True, None, 2) # Attempt to remove a non-existing template. The call must succeed but # Dibbler must not delete any files. assert dibbler.deleteTemplate('blah') == (True, None, 0) assert dibbler.getNumFiles() == (True, None, 2) # Delete the one remaining template (Raw template) and verify that # Dibbler does not hold any files anymore whatsoever afterwards. assert dibbler.deleteTemplate('name11') == (True, None, 2) assert dibbler.getNumFiles() == (True, None, 0) with pytest.raises(AssertionError): self.verifyRaw(ret_raw.data['url_frag'], 'foo', frag_raw) with pytest.raises(AssertionError): self.verifyRaw(ret_dae.data['url_frag'], 'bar', frag_dae)
def test_setFragments_raw(self, client_type): """ Spawn a new object and modify its geometry at runtime. """ # Get the client for this test. client = self.clients[client_type] # Convenience. objID = 1 # Add a new template and spawn it. frag = {'bar': getFragRaw()} temp = getTemplate('t1', fragments=frag) assert client.addTemplates([temp]).ok new_obj = {'templateID': temp.aid, 'rbs': {'position': (1, 1, 1), 'velocityLin': (-1, -1, -1)}} ret = client.spawn([new_obj]) assert ret.ok and ret.data == [objID] del temp, new_obj, ret # Query the SV to obtain the 'version' value. ret = client.getRigidBodies(objID) assert ret.ok version = ret.data[objID]['rbs'].version # Fetch-, modify-, update- and verify the geometry. ret = client.getFragments([objID]) assert ret.ok assert ret.data[objID]['bar']['fragtype'] == 'RAW' # Download the fragment. base_url = 'http://{ip}:{port}'.format( ip=config.addr_webserver, port=config.port_webserver) url = base_url + ret.data[objID]['bar']['url_frag'] + '/model.json' for ii in range(10): assert ii < 8 try: tmp = urllib.request.urlopen(url).readall() break except urllib.request.URLError: time.sleep(0.2) tmp = json.loads(tmp.decode('utf8')) assert FragRaw(**tmp) == frag['bar'].fragdata # Change the fragment geometries. cmd = {objID: {k: v._asdict() for (k, v) in frag.items()}} assert client.setFragments(cmd).ok ret = client.getFragments([objID]) assert ret.ok assert ret.data[objID]['bar']['fragtype'] == 'RAW' # Download the fragment. url = base_url + ret.data[objID]['bar']['url_frag'] + '/model.json' tmp = urllib.request.urlopen(url).readall() tmp = json.loads(tmp.decode('utf8')) assert FragRaw(**tmp) == frag['bar'].fragdata # Ensure 'version' is different as well. ret = client.getRigidBodies(objID) assert ret.ok and (ret.data[objID]['rbs'].version != version)