diff --git a/storlets/gateway/gateways/docker/runtime.py b/storlets/gateway/gateways/docker/runtime.py index 6e6126e1..f59883eb 100644 --- a/storlets/gateway/gateways/docker/runtime.py +++ b/storlets/gateway/gateways/docker/runtime.py @@ -28,7 +28,7 @@ from contextlib import contextmanager from storlets.sbus import SBus from storlets.sbus.command import SBUS_CMD_EXECUTE -from storlets.sbus.datagram import FDMetadata, SBusExecuteDatagram +from storlets.sbus.datagram import SBusFileDescriptor, SBusExecuteDatagram from storlets.sbus import file_description as sbus_fd from storlets.sbus.client import SBusClient from storlets.sbus.client.exceptions import SBusClientException @@ -505,8 +505,8 @@ class StorletInvocationProtocol(object): self.data_write_fd = None self.metadata_read_fd = None self.metadata_write_fd = None - self.execution_str_read_fd = None - self.execution_str_write_fd = None + self.taskid_read_fd = None + self.taskid_write_fd = None self.task_id = None self._input_data_read_fd = None self._input_data_write_fd = None @@ -536,47 +536,35 @@ class StorletInvocationProtocol(object): @property def remote_fds(self): """ - File descriptors to be passed to container side + A list of sbus file descirptors passed to remote side """ - remote_fds = [self.input_data_read_fd, - self.execution_str_write_fd, - self.data_write_fd, - self.metadata_write_fd, - self.storlet_logger.getfd()] - - for source in self.extra_data_sources: - remote_fds.append(source['read_fd']) - return remote_fds - - @property - def remote_fds_metadata(self): - """ - Metadata about file descriptors to be passed to container side - """ - input_fd_metadata = FDMetadata( - sbus_fd.SBUS_FD_INPUT_OBJECT, - storage_metadata=self.srequest.user_metadata) - if self.srequest.user_metadata: - input_fd_metadata.storage_metadata.update( - self.srequest.user_metadata) + storlets_metadata = {} if self.srequest.has_range: - input_fd_metadata.storlets_metadata['start'] = \ - str(self.srequest.start) - input_fd_metadata.storlets_metadata['end'] = \ - str(self.srequest.end) - fds_metadata = [ - input_fd_metadata.to_dict(), - FDMetadata(sbus_fd.SBUS_FD_OUTPUT_TASK_ID).to_dict(), - FDMetadata(sbus_fd.SBUS_FD_OUTPUT_OBJECT).to_dict(), - FDMetadata(sbus_fd.SBUS_FD_OUTPUT_OBJECT_METADATA).to_dict(), - FDMetadata(sbus_fd.SBUS_FD_LOGGER).to_dict()] + storlets_metadata.update( + {'start': str(self.srequest.start), + 'end': str(self.srequest.end)}) + + fds = [SBusFileDescriptor(sbus_fd.SBUS_FD_INPUT_OBJECT, + self.input_data_read_fd, + storage_metadata=self.srequest.user_metadata, + storlets_metadata=storlets_metadata), + SBusFileDescriptor(sbus_fd.SBUS_FD_OUTPUT_TASK_ID, + self.taskid_write_fd), + SBusFileDescriptor(sbus_fd.SBUS_FD_OUTPUT_OBJECT, + self.data_write_fd), + SBusFileDescriptor(sbus_fd.SBUS_FD_OUTPUT_OBJECT_METADATA, + self.metadata_write_fd), + SBusFileDescriptor(sbus_fd.SBUS_FD_LOGGER, + self.storlet_logger.getfd())] for source in self.extra_data_sources: - fdmd = FDMetadata( + fd = SBusFileDescriptor( sbus_fd.SBUS_FD_INPUT_OBJECT, + source['read_fd'], storage_metadata=source['user_metadata']) - fds_metadata.append(fdmd.to_dict()) - return fds_metadata + fds.append(fd) + + return fds @contextmanager def _activate_invocation_descriptors(self): @@ -599,7 +587,7 @@ class StorletInvocationProtocol(object): if not self.srequest.has_fd: self._input_data_read_fd, self._input_data_write_fd = os.pipe() self.data_read_fd, self.data_write_fd = os.pipe() - self.execution_str_read_fd, self.execution_str_write_fd = os.pipe() + self.taskid_read_fd, self.taskid_write_fd = os.pipe() self.metadata_read_fd, self.metadata_write_fd = os.pipe() for source in self.extra_data_sources: @@ -627,7 +615,7 @@ class StorletInvocationProtocol(object): Close all of the container side descriptors """ fds = [self.data_write_fd, self.metadata_write_fd, - self.execution_str_write_fd] + self.taskid_write_fd] if not self.srequest.has_fd: fds.append(self.input_data_read_fd) fds.extend([source['read_fd'] for source in self.extra_data_sources]) @@ -639,7 +627,7 @@ class StorletInvocationProtocol(object): Close all of the host side descriptors """ fds = [self.data_read_fd, self.metadata_read_fd, - self.execution_str_read_fd] + self.taskid_read_fd] fds.extend([source['write_fd'] for source in self.extra_data_sources]) self._safe_close(fds) @@ -662,10 +650,10 @@ class StorletInvocationProtocol(object): with self.storlet_logger.activate(),\ self._activate_invocation_descriptors(): self._send_execute_command() - self._wait_for_read_with_timeout(self.execution_str_read_fd) + self._wait_for_read_with_timeout(self.taskid_read_fd) # TODO(kota_): need an assertion for task_id format - self.task_id = os.read(self.execution_str_read_fd, 10) - os.close(self.execution_str_read_fd) + self.task_id = os.read(self.taskid_read_fd, 10) + os.close(self.taskid_read_fd) def _send_execute_command(self): """ @@ -675,7 +663,6 @@ class StorletInvocationProtocol(object): dtg = SBusExecuteDatagram( SBUS_CMD_EXECUTE, self.remote_fds, - self.remote_fds_metadata, self.srequest.params) rc = SBus.send(self.storlet_pipe_path, dtg) diff --git a/storlets/sbus/client/__init__.py b/storlets/sbus/client/__init__.py index df8b680b..56b19f30 100644 --- a/storlets/sbus/client/__init__.py +++ b/storlets/sbus/client/__init__.py @@ -18,7 +18,7 @@ from storlets.sbus import SBus from storlets.sbus.command import SBUS_CMD_CANCEL, SBUS_CMD_DAEMON_STATUS, \ SBUS_CMD_HALT, SBUS_CMD_PING, SBUS_CMD_START_DAEMON, \ SBUS_CMD_STOP_DAEMON, SBUS_CMD_STOP_DAEMONS -from storlets.sbus.datagram import FDMetadata, SBusServiceDatagram +from storlets.sbus.datagram import SBusFileDescriptor, SBusServiceDatagram from storlets.sbus.file_description import SBUS_FD_SERVICE_OUT from storlets.sbus.client.exceptions import SBusClientIOError, \ SBusClientMalformedResponse, SBusClientSendError @@ -61,8 +61,8 @@ class SBusClient(object): try: try: datagram = SBusServiceDatagram( - command, [write_fd], - [FDMetadata(SBUS_FD_SERVICE_OUT).to_dict()], + command, + [SBusFileDescriptor(SBUS_FD_SERVICE_OUT, write_fd)], params, task_id) rc = SBus.send(self.socket_path, datagram) if rc < 0: diff --git a/storlets/sbus/datagram.py b/storlets/sbus/datagram.py index e97d4d3f..33430a1b 100644 --- a/storlets/sbus/datagram.py +++ b/storlets/sbus/datagram.py @@ -19,25 +19,33 @@ from storlets.sbus import file_description as sbus_fd from storlets.sbus.command import SBUS_CMD_EXECUTE -class FDMetadata(object): - def __init__(self, fdtype, storlets_metadata=None, storage_metadata=None): +class SBusFileDescriptor(object): + """ + The management class for the file descriptor information + """ + + def __init__(self, fdtype, fileno, storlets_metadata=None, + storage_metadata=None): self.fdtype = fdtype + self.fileno = fileno self.storlets_metadata = storlets_metadata or {} self.storage_metadata = storage_metadata or {} - def to_dict(self): + @property + def metadata(self): storlets_metadata = copy.deepcopy(self.storlets_metadata) storlets_metadata['type'] = self.fdtype return {'storlets': storlets_metadata, 'storage': self.storage_metadata} @classmethod - def from_dict(cls, metadict): + def from_metadata_dict(cls, metadict): _metadict = copy.deepcopy(metadict) storlets_metadata = _metadict['storlets'] storage_metadata = _metadict['storage'] + fileno = _metadict['fileno'] fdtype = storlets_metadata.pop('type') - return cls(fdtype, storlets_metadata, storage_metadata) + return cls(fdtype, fileno, storlets_metadata, storage_metadata) class SBusDatagram(object): @@ -49,15 +57,12 @@ class SBusDatagram(object): # list format _required_fd_types = None - def __init__(self, command, fds, metadata, params=None, task_id=None): + def __init__(self, command, sfds, params=None, task_id=None): """ Create SBusDatagram instance :param command: A string encoding the command to send - :param fds: A list of file descriptors (integer) to pass with - the command - :param metadata: A list of dictionaries, where the i'th dictionary - is the metadata of the i'th fd. + :param sfds: A list of SBusFileDescriptor instances :param params: A optional dictionary with parameters for the command execution :param task_id: An optional string task id. This is currently used for @@ -67,17 +72,15 @@ class SBusDatagram(object): raise NotImplementedError( 'SBusDatagram class should not be initialized as bare') self.command = command - self._check_fd_nums(fds, metadata) - fd_types = [md['storlets']['type'] for md in metadata] + fd_types = [sfd.fdtype for sfd in sfds] self._check_required_fd_types(fd_types) - self.fds = fds - self.metadata = metadata + self.sfds = sfds self.params = params self.task_id = task_id @property def num_fds(self): - return len(self.fds) + return len(self.sfds) @property def cmd_params(self): @@ -92,19 +95,30 @@ class SBusDatagram(object): def serialized_cmd_params(self): return json.dumps(self.cmd_params) + @property + def fds(self): + """ + A list of raw file descriptors + """ + return [sfd.fileno for sfd in self.sfds] + + @property + def metadata(self): + return [sfd.metadata for sfd in self.sfds] + @property def serialized_metadata(self): return json.dumps(self.metadata) @property def object_in_metadata(self): - return [md['storage'] for md in self.metadata - if md['storlets']['type'] == sbus_fd.SBUS_FD_INPUT_OBJECT] + return [sfd.storage_metadata for sfd in self.sfds + if sfd.fdtype == sbus_fd.SBUS_FD_INPUT_OBJECT] @property def object_in_storlet_metadata(self): - return [md['storlets'] for md in self.metadata - if md['storlets']['type'] == sbus_fd.SBUS_FD_INPUT_OBJECT] + return [fd.storlets_metadata for fd in self.sfds + if fd.fdtype == sbus_fd.SBUS_FD_INPUT_OBJECT] def _find_fds(self, fdtype): """ @@ -113,11 +127,7 @@ class SBusDatagram(object): :param fdtype: file descriptor type :returns: a list of file descriptors """ - ret = [] - for i in range(len(self.metadata)): - if self.metadata[i]['storlets']['type'] == fdtype: - ret.append(self.fds[i]) - return ret + return [sfd.fileno for sfd in self.sfds if sfd.fdtype == fdtype] def _find_fd(self, fdtype): """ @@ -135,11 +145,6 @@ class SBusDatagram(object): # fd validation. return ret[0] - def _check_fd_nums(self, fds, metadata): - if len(fds) != len(metadata): - raise ValueError('Length mismatch fds:%s metadata:%s' - % (len(fds), len(metadata))) - def _check_required_fd_types(self, given_fd_types): if self._required_fd_types is None: raise NotImplementedError( @@ -176,9 +181,9 @@ class SBusServiceDatagram(SBusDatagram): """ _required_fd_types = [sbus_fd.SBUS_FD_SERVICE_OUT] - def __init__(self, command, fds, metadata, params=None, task_id=None): + def __init__(self, command, sfds, params=None, task_id=None): super(SBusServiceDatagram, self).__init__( - command, fds, metadata, params, task_id) + command, sfds, params, task_id) @property def service_out_fd(self): @@ -192,7 +197,7 @@ class SBusExecuteDatagram(SBusDatagram): sbus_fd.SBUS_FD_OUTPUT_OBJECT_METADATA, sbus_fd.SBUS_FD_LOGGER] - def __init__(self, command, fds, metadata, params=None, task_id=None): + def __init__(self, command, sfds, params=None, task_id=None): # TODO(kota_): the args command is not used in ExecuteDatagram # but it could be worthful to taransparent init # for other datagram classes. @@ -202,16 +207,15 @@ class SBusExecuteDatagram(SBusDatagram): # this implementation is based on the idea that # we only have extra input sources, which is # added at the end of fd list - extra_fd_types = [ - md['storlets']['type'] == sbus_fd.SBUS_FD_INPUT_OBJECT - for md in metadata[len(self._required_fd_types):]] + extra_fd_types = [sfd.fdtype for sfd in + sfds[len(self._required_fd_types):]] - if not all(extra_fd_types): + if [t for t in extra_fd_types if t != sbus_fd.SBUS_FD_INPUT_OBJECT]: raise ValueError( - 'Extra data should be SBUS_FD_INPUT_OBJECT: %' % metadata) + 'Extra data should be SBUS_FD_INPUT_OBJECT') super(SBusExecuteDatagram, self).__init__( - SBUS_CMD_EXECUTE, fds, metadata, params, task_id) + SBUS_CMD_EXECUTE, sfds, params, task_id) @property def object_out_fds(self): @@ -248,6 +252,15 @@ def build_datagram_from_raw_message(fds, str_md, str_cmd_params): command = cmd_params.get('command') params = cmd_params.get('params') task_id = cmd_params.get('task_id') + + if len(fds) != len(metadata): + raise ValueError('Length mismatch fds: %d != md %d' % + (len(fds), len(metadata))) + sfds = [] + for fileno, md in zip(fds, metadata): + md['fileno'] = fileno + sfds.append(SBusFileDescriptor.from_metadata_dict(md)) + if command == SBUS_CMD_EXECUTE: - return SBusExecuteDatagram(command, fds, metadata, params, task_id) - return SBusServiceDatagram(command, fds, metadata, params, task_id) + return SBusExecuteDatagram(command, sfds, params, task_id) + return SBusServiceDatagram(command, sfds, params, task_id) diff --git a/tests/unit/agent/common/test_server.py b/tests/unit/agent/common/test_server.py index 46ed194a..37d8029e 100644 --- a/tests/unit/agent/common/test_server.py +++ b/tests/unit/agent/common/test_server.py @@ -18,7 +18,7 @@ import unittest from storlets.sbus import command as sbus_cmd from storlets.sbus.file_description import SBUS_FD_SERVICE_OUT -from storlets.sbus.datagram import FDMetadata, SBusServiceDatagram +from storlets.sbus.datagram import SBusFileDescriptor, SBusServiceDatagram from storlets.agent.common.server import EXIT_SUCCESS, command_handler, \ CommandResponse, CommandFailure, CommandSuccess, SBusServer from tests.unit import FakeLogger @@ -150,12 +150,11 @@ class TestSBusServerMain(unittest.TestCase): self.server = self._get_test_server() def _test_main_loop_stop(self, stop_command): - metadata = [FDMetadata(SBUS_FD_SERVICE_OUT).to_dict()] + sfds = [SBusFileDescriptor(SBUS_FD_SERVICE_OUT, 1)] scenario = [ ('create', 1), ('listen', 1), - ('receive', SBusServiceDatagram(command=stop_command, fds=[1], - metadata=metadata, + ('receive', SBusServiceDatagram(command=stop_command, sfds=sfds, params=None, task_id=None)), ] diff --git a/tests/unit/sbus/test_datagram.py b/tests/unit/sbus/test_datagram.py index 9f6d55b9..e1e7e917 100644 --- a/tests/unit/sbus/test_datagram.py +++ b/tests/unit/sbus/test_datagram.py @@ -16,7 +16,7 @@ import json import unittest import storlets.sbus.file_description as sbus_fd -from storlets.sbus.datagram import FDMetadata, SBusDatagram, \ +from storlets.sbus.datagram import SBusFileDescriptor, SBusDatagram, \ SBusServiceDatagram, SBusExecuteDatagram, build_datagram_from_raw_message from storlets.sbus.command import SBUS_CMD_PING, SBUS_CMD_EXECUTE @@ -29,28 +29,27 @@ ALL_FD_TYPES = [ ] -class TestFDMetadata(unittest.TestCase): - def setUp(self): - pass +class TestSBusFileDescriptor(unittest.TestCase): + def test_metadata(self): + fd = SBusFileDescriptor( + 'MYTYPE', 1, {'storlets_key': 'storlets_value'}, + {'storage_key': 'storage_value'}) + self.assertEqual( + {'storlets': {'type': 'MYTYPE', 'storlets_key': 'storlets_value'}, + 'storage': {'storage_key': 'storage_value'}}, + fd.metadata) - def test_to_dict(self): - md = FDMetadata('MYTYPE', {'storlets_key': 'storlets_value'}, - {'storage_key': 'storage_value'}) - self.assertEqual({'storlets': {'type': 'MYTYPE', - 'storlets_key': 'storlets_value'}, - 'storage': {'storage_key': 'storage_value'}}, - md.to_dict()) - - def test_from_dict(self): - md = FDMetadata.from_dict( - {'storlets': {'type': 'MYTYPE', - 'storlets_key': 'storlets_value'}, - 'storage': {'storage_key': 'storage_value'}}) - self.assertEqual('MYTYPE', md.fdtype) + def test_from_metadata_dict(self): + fd = SBusFileDescriptor.from_metadata_dict( + {'storlets': {'type': 'MYTYPE', 'storlets_key': 'storlets_value'}, + 'storage': {'storage_key': 'storage_value'}, + 'fileno': 1}) + self.assertEqual(1, fd.fileno) + self.assertEqual('MYTYPE', fd.fdtype) self.assertEqual({'storlets_key': 'storlets_value'}, - md.storlets_metadata) + fd.storlets_metadata) self.assertEqual({'storage_key': 'storage_value'}, - md.storage_metadata) + fd.storage_metadata) class TestSBusDatagram(unittest.TestCase): @@ -78,13 +77,12 @@ class SBusDatagramTestMixin(object): def setUp(self): self.params = {'param1': 'paramvalue1'} self.task_id = 'id' - self.dtg = self._test_class(self.command, self.fds, self.metadata, + self.dtg = self._test_class(self.command, self.sfds, self.params, self.task_id) def test_init(self): self.assertEqual(self.command, self.dtg.command) - self.assertEqual(self.fds, self.dtg.fds) - self.assertEqual(self.metadata, self.dtg.metadata) + self.assertEqual(self.sfds, self.dtg.sfds) self.assertEqual(self.params, self.dtg.params) self.assertEqual(self.task_id, self.dtg.task_id) @@ -97,10 +95,6 @@ class SBusDatagramTestMixin(object): 'task_id': self.task_id}, self.dtg.cmd_params) - def test_serialized_metadata(self): - self.assertEqual(self.metadata, - json.loads(self.dtg.serialized_metadata)) - def test_serialized_cmd_params(self): res = {'command': self.command, 'params': self.params, @@ -121,10 +115,6 @@ class SBusDatagramTestMixin(object): self.assertTrue(cm.exception.args[0].startswith( 'Fd type mismatch given_fd_types')) - def test_check_fd_nums(self): - with self.assertRaises(ValueError): - self.dtg._check_fd_nums([], self.metadata) - def test_find_fds(self): # prepare all fd types and then pop out in the loop below not_in_fd_types = ALL_FD_TYPES[:] @@ -161,11 +151,11 @@ class SBusDatagramTestMixin(object): not_in_fd_types.remove(fd_type) # sanity, not a fd type results in None - self.assertIs(None, self.dtg._find_fd('DUMMY_TYPE')) + self.assertIsNone(self.dtg._find_fd('DUMMY_TYPE')) # sanity, no other types are found for fd_type in not_in_fd_types: - self.assertIs(None, self.dtg._find_fd(fd_type)) + self.assertIsNone(self.dtg._find_fd(fd_type)) class TestSBusServiceDatagram(SBusDatagramTestMixin, unittest.TestCase): @@ -174,8 +164,7 @@ class TestSBusServiceDatagram(SBusDatagramTestMixin, unittest.TestCase): def setUp(self): self.command = 'SBUS_CMD_TEST' self.types = [sbus_fd.SBUS_FD_SERVICE_OUT] - self.fds = [1] - self.metadata = [FDMetadata(sbus_fd.SBUS_FD_SERVICE_OUT).to_dict()] + self.sfds = [SBusFileDescriptor(sbus_fd.SBUS_FD_SERVICE_OUT, 1)] super(TestSBusServiceDatagram, self).setUp() def test_service_out_fd(self): @@ -192,11 +181,11 @@ class TestSBusExecuteDatagram(SBusDatagramTestMixin, unittest.TestCase): sbus_fd.SBUS_FD_OUTPUT_OBJECT, sbus_fd.SBUS_FD_OUTPUT_OBJECT_METADATA, sbus_fd.SBUS_FD_LOGGER] - self.fds = [i + 1 for i in range(len(self.types))] - self.metadata = [FDMetadata(self.types[i], - {'key%d' % i: 'value%d' % i}, - {'skey%d' % i: 'svalue%d' % i}).to_dict() - for i in range(len(self.types))] + self.sfds = [SBusFileDescriptor( + self.types[i], i + 1, + {'key%d' % i: 'value%d' % i}, + {'skey%d' % i: 'svalue%d' % i}) + for i in range(len(self.types))] super(TestSBusExecuteDatagram, self).setUp() def test_init_extra_sources(self): @@ -208,17 +197,15 @@ class TestSBusExecuteDatagram(SBusDatagramTestMixin, unittest.TestCase): sbus_fd.SBUS_FD_INPUT_OBJECT, sbus_fd.SBUS_FD_INPUT_OBJECT, sbus_fd.SBUS_FD_INPUT_OBJECT] - fds = [i + 1 for i in range(len(types))] - metadata = [FDMetadata(types[i], - {'key%d' % i: 'value%d' % i}, - {'skey%d' % i: 'svalue%d' % i}).to_dict() - for i in range(len(types))] + fds = [SBusFileDescriptor(types[i], i + 1, + {'key%d' % i: 'value%d' % i}, + {'skey%d' % i: 'svalue%d' % i}) + for i in range(len(types))] dtg = self._test_class( - self.command, fds, metadata, self.params, self.task_id) - self.assertEqual(dtg.fds, fds) - self.assertEqual(dtg.metadata, metadata) - self.assertEqual(dtg.params, self.params) - self.assertEqual(dtg.task_id, self.task_id) + self.command, fds, self.params, self.task_id) + self.assertEqual(types, [sfd.fdtype for sfd in dtg.sfds]) + self.assertEqual(self.params, dtg.params) + self.assertEqual(self.task_id, dtg.task_id) def test_object_out_fds(self): self.assertEqual([3], self.dtg.object_out_fds) @@ -250,20 +237,18 @@ class TestBuildDatagramFromRawMessage(unittest.TestCase): # SBusServiceDatagram scenario command = SBUS_CMD_PING types = [sbus_fd.SBUS_FD_SERVICE_OUT] - fds = [1] - metadata = [FDMetadata(sbus_fd.SBUS_FD_SERVICE_OUT).to_dict()] + fds = [SBusFileDescriptor(sbus_fd.SBUS_FD_SERVICE_OUT, 1)] params = {'param1': 'paramvalue1'} task_id = 'id' cmd_params = {'command': command, 'params': params, 'task_id': task_id} - str_metadata = json.dumps(metadata) + str_metadata = json.dumps([fd.metadata for fd in fds]) str_cmd_params = json.dumps(cmd_params) dtg = build_datagram_from_raw_message(fds, str_metadata, str_cmd_params) self.assertEqual(command, dtg.command) - self.assertEqual(fds, dtg.fds) - self.assertEqual(metadata, dtg.metadata) + self.assertEqual(types, [sfd.fdtype for sfd in dtg.sfds]) self.assertEqual(params, dtg.params) self.assertEqual(task_id, dtg.task_id) @@ -277,23 +262,21 @@ class TestBuildDatagramFromRawMessage(unittest.TestCase): sbus_fd.SBUS_FD_INPUT_OBJECT, sbus_fd.SBUS_FD_INPUT_OBJECT, sbus_fd.SBUS_FD_INPUT_OBJECT] - fds = [i + 1 for i in range(len(types))] - metadata = [FDMetadata(types[i], - {'key%d' % i: 'value%d' % i}, - {'skey%d' % i: 'svalue%d' % i}).to_dict() - for i in range(len(types))] + fds = [SBusFileDescriptor(types[i], i + 1, + {'key%d' % i: 'value%d' % i}, + {'skey%d' % i: 'svalue%d' % i}) + for i in range(len(types))] params = {'param1': 'paramvalue1'} task_id = 'id' cmd_params = {'command': command, 'params': params, 'task_id': task_id} - str_metadata = json.dumps(metadata) + str_metadata = json.dumps([fd.metadata for fd in fds]) str_cmd_params = json.dumps(cmd_params) dtg = build_datagram_from_raw_message(fds, str_metadata, str_cmd_params) self.assertEqual(command, dtg.command) - self.assertEqual(fds, dtg.fds) - self.assertEqual(metadata, dtg.metadata) + self.assertEqual(types, [sfd.fdtype for sfd in dtg.sfds]) self.assertEqual(params, dtg.params) self.assertEqual(task_id, dtg.task_id)