Esempio n. 1
0
    def setUp(self) -> None:
        self.config = EmulatorConfig()
        self.config.set_delay(0)

        self.output = mock.create_autospec(OutputInterface)
        self.output.available.return_value = True
        self.config.set_output(self.output)
Esempio n. 2
0
 def initialize_emu_conf(self):
     """ Initializes a new configuration for a new emulator object. The config and emulator are completely
     re-initialized, but properties that are defined in the persistent settings are reapplied """
     # Close the old config's in and output.
     if self.config is not None and hasattr(
             self.config, 'input') and hasattr(self.config.input, 'file'):
         self.config.input.file.close()
     elif self.config is not None and hasattr(
             self.config, 'input') and hasattr(self.config.input, 'serial'):
         self.config.input.serial.close()
     # Create a new config
     new_config = EmulatorConfig()
     self.decorate_config(
         new_config
     )  # decorate the new config, such that yaml scenarios loaded are processed by
     # our custom interpreter, which filters the GUI properties.
     self.override_values = {
     }  # Remove any overrides that were previously set (for an older config)
     new_config.set_config_file(self.current_config_name)
     new_config.generator_dict = dict()  # Ensure the generators are empty
     new_config.hex_generator_dict = dict()
     self.reload_persistent_settings(
         new_config)  # Apply the persistent settings
     new_config.create_scenarios(
     )  # Deserialize the scenario structure into scenario instances.
     new_emulator = Emulator(
         new_config)  # Start an emulator with the new config.
     self.config = new_config  # Replace the old config with the new config
     self.emulator = new_emulator  # Replace the old emulator with the new emulator
     logging.shutdown()  # Clear all old open log handles.
     # Announce the current, relevant data through broadcasts:
     self.current_overrides()
     self.current_config()
     self.current_status()
Esempio n. 3
0
    def setUp(self) -> None:
        self.config = EmulatorConfig()
        self.config.set_config(self.emulator_config)
        self.config.set_delay(0)
        self.config.create_scenarios()

        self.input = TestInput()
        self.config.set_input(self.input)

        self.output = mock.create_autospec(OutputInterface)
        self.output.available.return_value = True
        self.config.set_output(self.output)

        self.emulator = Emulator(self.config)
Esempio n. 4
0
class TextIntegrationTestCase(unittest.TestCase):
    def setUp(self) -> None:
        self.config = EmulatorConfig()
        self.config.set_delay(0)

        self.output = mock.create_autospec(OutputInterface)
        self.output.available.return_value = True
        self.config.set_output(self.output)

    def test_int_fixed_in_message(self):
        """
        Test the IntFixed scenario in an integration test
        """
        self.config.set_config("""
            device: Device
            name: TextTest
            protocol: text
            fields: 
              - name: Voltage
                key: V
                values:
                  - type: IntFixed
                    amount: 2
                    value: 1
            """)
        self.config.create_scenarios()
        emulator = Emulator(self.config)
        emulator.run()

        message_occurrences = 0
        for message in self.__get_outputted_messages():
            if b'\r\nV\t1' in message:
                message_occurrences += 1
        self.assertEqual(message_occurrences, 2)

    def test_string_fixed_in_message(self):
        """
        Test the StringFixed scenario in an integration test
        """
        self.config.set_config("""
            device: Device
            name: TextTest
            protocol: text
            fields: 
              - name: Voltage
                key: V
                values:
                  - type: StringFixed
                    amount: 2
                    value: ---
            """)
        self.config.create_scenarios()
        emulator = Emulator(self.config)
        emulator.run()

        message_occurrences = 0
        for message in self.__get_outputted_messages():
            if b'\r\nV\t---' in message:
                message_occurrences += 1
        self.assertEqual(message_occurrences, 2)

    def test_loop_in_message(self):
        """
        Test the Loop scenario in an integration test
        """
        self.config.set_config("""
            device: Device
            name: TextTest
            protocol: text
            fields: 
              - name: Voltage
                key: V
                values:
                  - type: Loop
                    amount: 2
                    values:
                      - type: IntFixed
                        amount: 2
                        value: 1
                      - type: IntFixed
                        amount: 2
                        value: 2
            """)
        self.config.create_scenarios()
        emulator = Emulator(self.config)
        emulator.run()

        message_values = []
        for message in self.__get_outputted_messages():
            if b'\r\nV\t1' in message:
                message_values.append(1)
            elif b'\r\nV\t2' in message:
                message_values.append(2)
        self.assertEqual(message_values, [1, 1, 2, 2, 1, 1, 2, 2])

    def test_arithmetic_in_message(self):
        """
        Test the Arithmetic scenario in an integration test
        """
        self.config.set_config("""
            device: Device
            name: TextTest
            protocol: text
            fields: 
              - name: Voltage
                key: V
                values:
                  - type: IntFixed
                    amount: 2
                    value: 2
              - name: Amperage
                key: A
                values:
                  - type: IntFixed
                    amount: 3
                    value: 3
              - name: Power
                key: W
                values:
                  - type: Arithmetic
                    value: V * A
            """)
        self.config.create_scenarios()
        emulator = Emulator(self.config)
        emulator.run()

        message_occurrences = 0
        for message in self.__get_outputted_messages():
            if b'\r\nW\t6' in message:
                message_occurrences += 1
        self.assertEqual(message_occurrences, 3)

    def test_bitbuffer_in_message(self):
        """
        Test the Bitbuffer scenario in an integration test
        """
        self.config.set_config("""
            device: Device
            name: TextTest
            protocol: text
            fields: 
              - name: Voltage
                key: V
                values:
                  - type: BitBuffer
                    values:
                      - type: IntFixed
                        bits: 5
                        amount: 2
                        value: 1
                      - type: IntFixed
                        bits: 3
                        amount: 3
                        value: 2
            """)
        self.config.create_scenarios()
        emulator = Emulator(self.config)
        emulator.run()

        message_occurrences = 0
        for message in self.__get_outputted_messages():
            if b'\r\nV\t10' in message:  # 10 = (1 << 3) + 2
                message_occurrences += 1
        self.assertEqual(message_occurrences, 2)

    def test_mapping_in_message(self):
        """
        Test the Mapping scenario in an integration test
        """
        self.config.set_config("""
            device: Device
            name: TextTest
            protocol: text
            fields: 
              - name: Enabled
                key: E
                values:
                  - type: Mapping
                    amount: 2
                    dict: { 'OFF': 'OFF', 'ON': 'ON' }
            """)
        self.config.create_scenarios()
        emulator = Emulator(self.config)
        emulator.run()

        message_occurrences = 0
        for message in self.__get_outputted_messages():
            if b'\r\nE\tOFF' in message or b'\r\nE\tON' in message:  # 10 = (1 << 3) + 2
                message_occurrences += 1
        self.assertEqual(message_occurrences, 2)

    def test_preset_random_in_message(self):
        """
        Test the random preset
        """
        self.config.set_config("""
            device: Device
            name: TextTest
            protocol: text
            preset: test
            preset_fields:
              - v: random
            """)
        self.config.create_scenarios()
        emulator = Emulator(self.config)
        emulator.run()

        message_occurrences = 0
        for message in self.__get_outputted_messages():
            if b'\r\nV\t1' in message:
                message_occurrences += 1
        self.assertEqual(message_occurrences, 1)

    def test_checksum_in_message(self):
        """
        Check that a checksum is added to the message and that it is valid
        """
        self.config.set_config("""
            device: Device
            name: TextTest
            protocol: text
            fields: 
              - name: Voltage
                key: V
                unit: V
                values:
                  - type: IntFixed
                    amount: 2
                    value: 1
            """)
        self.config.create_scenarios()
        emulator = Emulator(self.config)
        emulator.run()

        checksums_valid = True
        for message in self.__get_outputted_messages():
            checksums_valid = message.count(
                b'Checksum') == 1  # Only one Checksum per message
            checksums_valid = checksums_valid and check_checksum(
                message)  # Checksum is valid
            if not checksums_valid:
                break
        self.assertTrue(checksums_valid)

    def test_not_split_message(self):
        """
        Check that a message is not split if it is not too long
        """
        fields = []
        for i in range(0, 21):
            fields.append({
                'name':
                chr(65 + i),
                'key':
                chr(65 + i),
                'values': [{
                    'type': 'IntFixed',
                    'amount': 1,
                    'value': 1
                }]
            })

        self.config.set_config_dict({
            'device': 'Device',
            'name': 'TextTest',
            'protocol': 'text',
            'fields': fields
        })
        self.config.create_scenarios()
        emulator = Emulator(self.config)
        emulator.run()

        messages = self.__get_outputted_messages()

        self.assertEqual(len(messages), 1)

    def test_split_message(self):
        """
        Check that a message that is too long is split into multiple messages
        """
        fields = []
        for i in range(0, 22):
            fields.append({
                'name':
                chr(65 + i),
                'key':
                chr(65 + i),
                'values': [{
                    'type': 'IntFixed',
                    'amount': 1,
                    'value': 1
                }]
            })

        self.config.set_config_dict({
            'device': 'Device',
            'name': 'TextTest',
            'protocol': 'text',
            'fields': fields
        })
        self.config.create_scenarios()
        emulator = Emulator(self.config)
        emulator.run()

        messages = self.__get_outputted_messages()

        self.assertEqual(len(messages), 2)

        messages_fields = []

        for message in messages:
            message_fields = []
            for line in message.split(b'\r\n'):
                field = line.split(b'\t')
                if len(field) == 2:
                    message_fields.append(field[0])
            messages_fields.append(message_fields)

        for message_fields in messages_fields:
            # Message has at most 22 fields
            self.assertLessEqual(len(message_fields), 22)

        # Verify that all fields are only sent once, apart from the Checksum, which should be in every message
        self.assertEqual([b'Checksum'], [
            field
            for field in messages_fields[0] if field in messages_fields[1]
        ])

    def test_bit_error(self):
        """
        Test if adding bit errors works properly
        We can unfortunately not unit test for corrupting the checksum since there is still a small chance that
        the checksum is still correct after adding bit errors
        """
        self.config.set_config("""
            device: Device
            name: TextTest
            protocol: text
            fields: 
              - name: Voltage
                key: V
                unit: V
                values:
                  - type: IntFixed
                    amount: 2
                    value: 1
            """)
        self.config.create_scenarios()
        self.config.set_bit_error_rate(0.5)
        self.config.set_bit_error_checksum(False)
        emulator = Emulator(self.config)
        emulator.run()

        for message in self.__get_outputted_messages():
            self.assertNotEqual(b'\r\nV\t1\r\nChecksum\t\x06',
                                message)  # Check if the message is corrupted
            self.assertTrue(check_checksum(
                message))  # Check if the checksum is still correct

    def test_determinism(self):
        """
        Test that the emulator is deterministic
        """
        self.config.set_config("""
            device: Device
            name: TextTest
            protocol: text
            fields: 
              - name: Voltage
                key: V
                unit: V
                values:
                  - type: IntRandom
                    amount: 100
                    min: -1000
                    max: 1000
            """)
        self.config.create_scenarios()
        emulator = Emulator(self.config)
        emulator.run()

        first_run_messages = self.__get_outputted_messages()

        # Reset output
        self.output = mock.create_autospec(OutputInterface)
        self.output.available.return_value = True
        self.config.set_output(self.output)

        # Do a second run
        self.config.create_scenarios()
        emulator = Emulator(self.config)
        emulator.run()

        second_run_messages = self.__get_outputted_messages()

        self.assertEqual(first_run_messages, second_run_messages)

    def __get_outputted_messages(self):
        """
        Get a list of messages that was written to the output
        :return: list of messages
        :rtype: list[bytes]
        """
        return [args.args[0] for args in self.output.write.call_args_list]
def main():
    """
    Run the main emulator program
    """
    config = EmulatorConfig()

    ascii_art()
    logger.info('Started')
    logger.info('Parsing config')
    config.set_config_file(file)
    config.set_input(input)
    config.set_output(output)
    config.set_delay(2)
    config.set_stop_condition('none')
    config.set_bit_error_rate(0.04)
    config.set_timed(False)
    logger.debug(f'Config parsed, fields: {config.get_fields()}')
    logger.info('Creating generators.')
    config.create_scenarios()
    logger.info('Generators created')

    logger.info('Emulation phase')
    emulator = Emulator(config)
    emulator.run()
    logger.info('Finished')
def emulate(cli_config, config, input, input_type, output, output_type, delay, stop_condition, bit_error_rate, timed):
    """
    This function runs the emulator with specified parameters
    """
    logger = cli_config.logger
    emulator_config = EmulatorConfig()
    ascii_art(logger)
    logger.info('Started')
    logger.info('Parsing config')
    emulator_config.set_config_file(config)

    if input_type == 'serial':
        emulator_config.set_input(SerialInput(input))
    elif input_type == 'file':
        emulator_config.set_input(FileInput(input))
    else:
        # This should never happen since Click filters the input
        raise ValueError

    if output is None and output_type is 'serial':
        raise ClickException('No serial port provided. Provide a serial port using the `--output` argument or use a different output type using `--output-type`. Run `vemulator-cli emulate --help` for more information.')
    if output_type == 'serial':
        emulator_config.set_output(SerialOutput(output))
    elif output_type == 'file':
        emulator_config.set_output(FileOutput(output))
    elif output_type == 'standard':
        emulator_config.set_output(StandardOutput())
    else:
        # This should never happen since Click filters the input
        raise ValueError

    emulator_config.set_delay(delay)
    # todo async_hex_persist docs in config
    emulator_config.set_stop_condition(stop_condition)
    emulator_config.set_bit_error_rate(bit_error_rate)
    emulator_config.set_timed(timed)
    logger.debug(f'Config parsed, fields: {emulator_config.get_fields()}')
    logger.info('Creating scenarios')
    emulator_config.create_scenarios()
    logger.info('Scenarios created')

    logger.info('Emulation phase')
    emulator = Emulator(emulator_config)
    emulator.run()
    logger.info('Finished')
Esempio n. 7
0
class HexIntegrationTestCase(unittest.TestCase):
    emulator_config = """
    device: Device
    name: HexTest
    protocol: text_hex
    version: 0x1234
    product_id: 0x5678
    fields: 
      - name: Voltage
        key: V
        unit: V
        values:
          - type: IntFixed
            amount: 1
            value: 1
    hex_fields: 
      - name: Voltage
        key: 0x1234
        unit: V
        values:
          - type: IntFixed
            amount: 2
            value: 0xF00F
            bits: 16
      - name: Amperage
        key: 0x1235
        unit: A
        writable: true
        values:
          - type: IntFixed
            amount: 2
            value: 0x0FF0
            bits: 16
      - name: VA
        key: 0x1236
        values:
          - type: BitBuffer
            values: 
              - type: IntFixed
                bits: 5
                amount: 2
                value: 1
              - type: IntFixed
                bits: 3
                amount: 3
                value: 2
    """

    def setUp(self) -> None:
        self.config = EmulatorConfig()
        self.config.set_config(self.emulator_config)
        self.config.set_delay(0)
        self.config.create_scenarios()

        self.input = TestInput()
        self.config.set_input(self.input)

        self.output = mock.create_autospec(OutputInterface)
        self.output.available.return_value = True
        self.config.set_output(self.output)

        self.emulator = Emulator(self.config)

    def test_boot(self):
        """
        Try sending a boot command
        """
        self.input.writeline(b':051FA51FA51FA51FA51FADE\n')
        self.emulator.run()
        self.output.write.assert_any_call(b':4000051\n')

    def test_ping(self):
        """
        Try sending a ping
        """
        self.input.writeline(b':154\n')
        self.emulator.run()
        self.output.write.assert_any_call(b':534120A\n')

    def test_version(self):
        """
        Try getting the firmware version
        """
        self.input.writeline(b':352\n')
        self.emulator.run()
        self.output.write.assert_any_call(b':134120E\n')

    def test_product_id(self):
        """
        Try getting the product id
        """
        self.input.writeline(b':451\n')
        self.emulator.run()
        self.output.write.assert_any_call(b':1785686\n')

    def test_get_exists(self):
        """
        Try getting an existing field
        """
        self.input.writeline(b':734120008\n')
        self.emulator.run()
        self.output.write.assert_any_call(b':73412000FF009\n')

    def test_get_not_exists(self):
        """
        Try getting a non-existing field
        """
        self.input.writeline(b':712340008\n')
        self.emulator.run()
        self.output.write.assert_any_call(b':712340107\n')

    def test_set_writable(self):
        """
        Try writing to a writable hex field
        """
        self.input.writeline(b':83512001234C0\n')
        self.emulator.run()
        self.output.write.assert_any_call(b':83512001234C0\n')

    def test_set_not_writable(self):
        """
        Try writing to a read-only hex field
        """
        self.input.writeline(b':83412001234C1\n')
        self.emulator.run()
        self.output.write.assert_any_call(b':83412020FF006\n')

    def test_set_not_exists(self):
        """
        Try writing a non-existing field
        """
        self.input.writeline(b':81234001234C1\n')
        self.emulator.run()
        self.output.write.assert_any_call(b':812340106\n')

    def test_set_invalid_size(self):
        """
        Try setting a field with too many bytes
        """
        self.input.writeline(b':83512001234566A\n')
        self.emulator.run()
        self.output.write.assert_any_call(b':8351204F00F03\n')

    def test_unknown_command(self):
        """
        Try sending an unknown command
        """
        self.input.writeline(b':253\n')
        self.emulator.run()
        self.output.write.assert_any_call(b':3020050\n')

    def test_invalid_checksum(self):
        """
        Try sending a command with an invalid checksum
        """
        self.input.writeline(b':155\n')
        self.emulator.run()
        self.output.write.assert_any_call(b':4AAAAFD\n')

    def test_bitbuffer(self):
        """
        Test the bitbuffer scenario
        """
        self.input.writeline(b':736120006\n')
        self.emulator.run()
        self.output.write.assert_any_call(b':73612000AFC\n')

    def test_preset_random_in_message(self):
        """
        Test the random hex preset
        """
        config = EmulatorConfig()
        config.set_config("""
            device: Device
            name: TextTest
            protocol: hex
            version: 0x1234
            product_id: 0x5678
            fields: 
              - name: Voltage
                key: V
                unit: V
                values:
                  - type: IntFixed
                    amount: 1
                    value: 1
            preset: test
            preset_hex_fields:
              - v_hex: random
            """)
        config.set_delay(0)
        config.create_scenarios()

        config.set_input(self.input)
        config.set_output(self.output)

        emulator = Emulator(config)

        self.input.writeline(b':734120008\n')
        emulator.run()
        self.output.write.assert_any_call(b':73412000FF009\n')
Esempio n. 8
0
    def test_preset_random_in_message(self):
        """
        Test the random hex preset
        """
        config = EmulatorConfig()
        config.set_config("""
            device: Device
            name: TextTest
            protocol: hex
            version: 0x1234
            product_id: 0x5678
            fields: 
              - name: Voltage
                key: V
                unit: V
                values:
                  - type: IntFixed
                    amount: 1
                    value: 1
            preset: test
            preset_hex_fields:
              - v_hex: random
            """)
        config.set_delay(0)
        config.create_scenarios()

        config.set_input(self.input)
        config.set_output(self.output)

        emulator = Emulator(config)

        self.input.writeline(b':734120008\n')
        emulator.run()
        self.output.write.assert_any_call(b':73412000FF009\n')