Beispiel #1
0
    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
Beispiel #2
0
    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
Beispiel #3
0
    def test_collada_model(self, client_type):
        """
        Add a template based on a Collada model, spawn it, and query its
        geometry.
        """
        # Get the client for this test.
        client = self.clients[client_type]

        # Add a valid template with Collada data and verify the upload worked.
        temp = getTemplate('foo', fragments={'f_dae': getFragDae()})
        assert client.addTemplates([temp]).ok

        # Spawn the template.
        ret = client.spawn([{'templateID': temp.aid}])
        assert ret.ok
        objID = ret.data[0]

        # Query and the geometry.
        ret = client.getFragments([objID])
        assert ret.ok

        # Verify it has the correct type ('DAE') and address.
        ret = ret.data[objID]
        assert ret['f_dae']['fragtype'] == 'DAE'
        assert ret['f_dae']['url_frag'] == (
            config.url_instances + '/' + str(objID) + '/f_dae')
Beispiel #4
0
    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)
Beispiel #5
0
    def test_addTemplate_with_no_fragments(self):
        """
        Add a template that has no fragments. This must still create a
        'meta.json' file (but nothing else).
        """
        # Create a Dibbler instance and flush all data.
        dibbler = self.dibbler
        assert dibbler.getNumFiles() == (True, None, 0)

        # Define a template for this test.
        t_raw = getTemplate('_templateEmpty')

        # Add the template and verify that the database now contains
        # exactly one file.
        ret = dibbler.addTemplate(t_raw)
        assert ret.ok
        assert dibbler.getNumFiles() == (True, None, 1)
        url = ret.data['url_frag']

        # Download the one- and only meta file and verify that it reports an
        # empty 'fragment' list.
        ret = self.dibbler.getFile('{}/meta.json'.format(url))
        assert ret.ok
        ret = json.loads(ret.data.decode('utf8'))
        assert ret['fragments'] == {}
Beispiel #6
0
    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)
Beispiel #7
0
    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)
Beispiel #8
0
    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
Beispiel #9
0
    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))
Beispiel #10
0
    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)
Beispiel #11
0
    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)
Beispiel #12
0
    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)
Beispiel #13
0
    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
Beispiel #14
0
    def test_addDaeTemplate(self):
        """
        Add a Collada template and fetch the individual files again afterwards.
        """
        dibbler = self.dibbler

        # Define a template for this test.
        frag = {'foo': getFragDae()}
        t_dae = getTemplate('_templateEmpty', fragments=frag)

        # Create a Dibbler instance and flush all data.
        assert dibbler.getNumFiles() == (True, None, 0)

        # Add the first template and verify that the database now contains
        # extactly fourc files (a meta file, the DAE file, and two textures).
        ret = dibbler.addTemplate(t_dae)
        assert dibbler.getNumFiles() == (True, None, 4)

        # Fetch- and verify the model.
        self.verifyDae(ret.data['url_frag'], 'foo', frag)
Beispiel #15
0
    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)
Beispiel #16
0
    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
Beispiel #17
0
    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)
Beispiel #18
0
    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']
Beispiel #19
0
    def test_controlParts(self, client_type):
        """
        Create a template with boosters and factories. Then send control
        commands to them and ensure the applied forces, torques, and
        spawned objects are correct.

        In this test the parent object moves and is oriented away from its
        default.
        """
        # Get the client for this test.
        client = self.clients[client_type]

        # Reset the SV database and instantiate a Leonard.
        leo = getLeonard()

        # Parameters and constants for this test.
        objID_1 = 1
        pos_parent = [1, 2, 3]
        vel_parent = [4, 5, 6]

        # Part positions relative to parent.
        dir_0 = [0, 0, +2]
        dir_1 = [0, 0, -1]
        pos_0 = [0, 0, +3]
        pos_1 = [0, 0, -4]

        # Describes a rotation of 180 degrees around x-axis.
        orient_parent = [1, 0, 0, 0]

        # Part position in world coordinates if the parent is rotated by 180
        # degrees around the x-axis. The normalisation of the direction is
        # necessary because the parts will automatically normalise all
        # direction vectors, including dir_0 and dir_1 which are not unit
        # vectors.
        dir_0_out = -np.array(dir_0) / np.sum(abs(np.array(dir_0)))
        dir_1_out = -np.array(dir_1) / np.sum(abs(np.array(dir_1)))
        pos_0_out = -np.array(pos_0)
        pos_1_out = -np.array(pos_1)

        # ---------------------------------------------------------------------
        # Create a template with two factories and spawn it.
        # ---------------------------------------------------------------------

        # Define the parts.
        boosters = {
            '0': types.Booster(pos=pos_0, direction=dir_0,
                               minval=0, maxval=0.5, force=0),
            '1': types.Booster(pos=pos_1, direction=dir_1,
                               minval=0, maxval=1.0, force=0)
        }
        factories = {
            '0': types.Factory(pos=pos_0, direction=dir_0,
                               templateID='_templateBox',
                               exit_speed=[0.1, 0.5]),
            '1': types.Factory(pos=pos_1, direction=dir_1,
                               templateID='_templateSphere',
                               exit_speed=[1, 5])
        }

        # Define the template, add it to Azrael, and spawn an instance.
        temp = getTemplate('t1',
                           rbs=getRigidBody(),
                           boosters=boosters,
                           factories=factories)
        assert client.addTemplates([temp]).ok
        new_obj = {'templateID': temp.aid,
                   'rbs': {
                       'position': pos_parent,
                       'velocityLin': vel_parent,
                       'rotation': orient_parent}}
        ret = client.spawn([new_obj])
        assert ret.ok and (ret.data == [objID_1])
        del boosters, factories, temp, new_obj

        # ---------------------------------------------------------------------
        # Activate booster and factories and verify that the applied force and
        # torque is correct, as well as that the spawned objects have the
        # correct state variables attached to them.
        # ---------------------------------------------------------------------

        # Create the commands to let each factory spawn an object.
        exit_speed_0, exit_speed_1 = 0.2, 2
        forcemag_0, forcemag_1 = 0.2, 0.4
        cmd_b = {
            '0': types.CmdBooster(force=forcemag_0),
            '1': types.CmdBooster(force=forcemag_1),
        }
        cmd_f = {
            '0': types.CmdFactory(exit_speed=exit_speed_0),
            '1': types.CmdFactory(exit_speed=exit_speed_1),
        }

        # Send the commands and ascertain that the returned object IDs now
        # exist in the simulation. These IDs must be '2' and '3'.
        ret = client.controlParts(objID_1, cmd_b, cmd_f)
        id_2, id_3 = 2, 3
        assert (ret.ok, ret.data) == (True, [id_2, id_3])

        # Query the state variables of the objects spawned by the factories.
        ok, _, ret_SVs = client.getRigidBodies([id_2, id_3])
        assert (ok, len(ret_SVs)) == (True, 2)

        # Determine which body was spawned by which factory based on their
        # position. We do this by looking at their initial position which
        # *must* match one of the parents.
        body_2, body_3 = ret_SVs[id_2]['rbs'], ret_SVs[id_3]['rbs']
        if np.allclose(body_2.position, pos_1_out + pos_parent):
            body_2, body_3 = body_3, body_2

        # Verify the position and velocity of the spawned objects is correct.
        ac = np.allclose
        assert ac(body_2.velocityLin, exit_speed_0 * dir_0_out + vel_parent)
        assert ac(body_2.position, pos_0_out + pos_parent)
        assert ac(body_3.velocityLin, exit_speed_1 * dir_1_out + vel_parent)
        assert ac(body_3.position, pos_1_out + pos_parent)

        # Let Leonard sync its data and then verify it received the correct
        # total force and torque exerted by the boosters.
        leo.processCommandsAndSync()
        forcevec_0, forcevec_1 = forcemag_0 * dir_0_out, forcemag_1 * dir_1_out
        tot_force = forcevec_0 + forcevec_1
        tot_torque = (np.cross(pos_0_out, forcevec_0) +
                      np.cross(pos_1_out, forcevec_1))

        # Query the torque and force from Azrael and verify they are correct.
        leo_force, leo_torque = leo.totalForceAndTorque(objID_1)
        assert np.array_equal(leo_force, tot_force)
        assert np.array_equal(leo_torque, tot_torque)
Beispiel #20
0
    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)
Beispiel #21
0
    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)
Beispiel #22
0
    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)
Beispiel #23
0
    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