Unit tests

Tests for driver implementation

Tests for IM871-A driver. Uses mocked tests when not on Gateway. On Gateway, tests run using hardware peripheral.

Future dev.:

  • Try spec=True to investigate if MagicMock can correctly spec the patched classes and functions.

  • E.g. when patching serial.Serial, the MagicMock should appear to have all relevant methods.

  • This could eliminate some need for spec’ing our own test doubles (fakes).

test.test_DriverClass.IM871A_pipe()[source]

Fixture that returns a path to use for the pipe

class test.test_DriverClass.PatchSerial(read_raw_return)[source]

Fakes the serial.Serial object. Avoids attempts of write/read operations from /dev/tty devices on local machines.

close()[source]
read(num_bytes)[source]
write(message_bytes)[source]
class test.test_DriverClass.PipeWriter[source]

Fakes the builtin method used to open a pipe and write to it. This avoids pipes being opened on local machines.

close()[source]
flush()[source]
write(message)[source]
test.test_DriverClass.input_data()[source]

Fixture that returns raw usb data, processed data and processed data with errors

test.test_DriverClass.is_on_gateway()[source]

Returns true if this is the gateway

test.test_DriverClass.patched_driver(mock_obj_im871a_port, mock_obj_fifo, mock_obj_serial_conn, mock_open)[source]

Make a driver fixture where we’ve patched (bypass/override) the port.Serial dependency with our own fake object. The port.Serial-function (serial.Serial) is used when the driver tries to establish serial connection. Patch os.mkfifo to prevent making FIFO (pipe) in the local OS during object construction. Set up that we test on one specific test vector.

test.test_DriverClass.test_CRC_check_fails_RPi(IM871A_pipe, input_data)[source]

Tests if a unsuccesfull CRC-check returns false

test.test_DriverClass.test_CRC_check_succes_RPi(IM871A_pipe, input_data)[source]

Tests if a succesfull CRC-check returns true

test.test_DriverClass.test_close(patched_driver)[source]
test.test_DriverClass.test_constructor_destructor(patched_driver)[source]

Test construction and destruction of a driver object is OK.

test.test_DriverClass.test_linkmodes_RPi(IM871A_pipe)[source]

Testing all the linkmodes possible with IM871A

test.test_DriverClass.test_object_instatiated_true_RPi(IM871A_pipe)[source]

Testing if an object of the type IM871A can be instantiated

test.test_DriverClass.test_read_data(patched_driver)[source]

Already Patch out the pipe dependency to an instance of local PipeWriter-type object that we can easily read.

test.test_DriverClass.test_read_data_RPi(IM871A_pipe, input_data)[source]

Testing if it’s possible to read from the pipe

test.test_DriverClass.test_setup_linkmode(patched_driver)[source]
test.test_DriverClass.test_usb_essentials_RPi(IM871A_pipe)[source]

Testing if it is possible to open the pipe and reset the USB-module

test.test_DriverClass.test_vectors()[source]

Build test set of raw serial data and ascii (processed) data.

Tests for OmniPower implementation

Tests for the functionality of OmniPower implementation.

test.test_OmniPower.bad_payload_list()[source]

Sets up a mangled telegram.

test.test_OmniPower.bad_telegrams_list()[source]

Sets up a list of bad telegrams that must cause exceptions at various places.

test.test_OmniPower.good_telegrams_list()[source]

Sets up a list of good telegrams.

test.test_OmniPower.omnipower_base()[source]

Creates an good OmniPower object with no data in log.

test.test_OmniPower.omnipower_setup(omnipower_base)[source]

Sets up an omnipower test fixture with at least one telegram stored in log.

test.test_OmniPower.omnipower_with_no_aes_key(omnipower_base)[source]

Creates a good OmniPower object with empty AES key.

test.test_OmniPower.test_Omnipower_longtelegram(omnipower_base)[source]

Assure Omnipower class can process long telegrams

test.test_OmniPower.test_Omnipower_noAESkey(omnipower_base)[source]

Assure that Omnipower class can’t decrypt with wrong or no AES-key

test.test_OmniPower.test_Omnipower_notmytelegram(omnipower_base)[source]

Assure Omnipower class rejects a telegram from an unknown sensor

test.test_OmniPower.test_Omnipower_shorttelegram(omnipower_base)[source]

Assure Omnipower class can process long telegrams

test.test_OmniPower.test_c1telegram_must_raise_exception(bad_telegrams_list)[source]

Test that C1 Telegram initialized with bad bytestream raises exception.

test.test_OmniPower.test_decrypt_must_raise_aes_key_error(omnipower_with_no_aes_key, good_telegrams_list)[source]

If AES key is not OK, decrypt must raise an AesKeyException.

test.test_OmniPower.test_decrypt_must_raise_crc_check_error(omnipower_base, bad_payload_list)[source]

If the payload has been modified or mangled, CRC16 check must fail, and a CrcCheckException is raised, which passes through .decrypt().

test.test_OmniPower.test_decrypt_using_must_return_false_for_bad_key(omnipower_with_no_aes_key, good_telegrams_list)[source]

Decrypt_using is the telegram that attempts to decrypt itself using a meter object. If the AES key in the meter object is bad, it cannot be used for decryption. Then decrypt_using must return False to signify failed operation. Test strategy: Good telegram + bad AES key -> AesKeyException.

test.test_OmniPower.test_decrypt_using_must_return_false_for_bad_payload(omnipower_base, bad_payload_list)[source]

Decrypt_using is the telegram that attempts to decrypt itself using a meter object. If the payload is bad, the meter object cannot successfully validate CRC16. Then decrypt_using must return False to signify failed operation. Test strategy: Bad payload + good AES key -> CrcCheckException.

test.test_OmniPower.test_extract_measurement_frame_returns_empty_if_tlg_not_decrypted(omnipower_base, good_telegrams_list)[source]

Expect OmniPower’s extract_measurement_frame to return an empty object if the telegram has not been decrypted, so there is no data to extract. Per spec., it must then return an empty object. Test strategy, used the implemented method .is_empty() to test this.

test.test_OmniPower.test_json_full_log(omnipower_setup)[source]

Test that a full log of MeterMeasurement objects dumped to JSON can all be recovered correctly.

test.test_OmniPower.test_process_telegram_returns_false_if_not_parsable(omnipower_base, good_telegrams_list)[source]

Expect OmniPower’s process_telegram to return False if the telegram cannot be parsed / handled by OmniPower. Reasons:

  • Not sent from this meter

  • decrypt_using returns false (tested above)

  • empty frame returned (tested above)

  • add_measurement_to_log fails (not tested)

Tests for MeterMeasurement implementation

Tests for the functionality of MeterMeasurement implementation.

test.test_MeterMeasure.MeasureFix()[source]

Setup-fixture for Measurement-class

test.test_MeterMeasure.initialized_measurement_frame()[source]

Sets up a measurement frame with ID and fixed Zulu timestamp, but no data.

test.test_MeterMeasure.keys()[source]

Setup-fixture for keys

test.test_MeterMeasure.omnipower_setup()[source]

Sets up an omnipower test fixture with at least one telegram stored in log.

test.test_MeterMeasure.test_add_measurement(MeasureFix, keys)[source]

Test the “add_measurement”-method from MeterMeasurement

test.test_MeterMeasure.test_as_dict(MeasureFix, keys)[source]

Test the “as_dict” method from MeterMeasurement

test.test_MeterMeasure.test_json_single_measurement(omnipower_setup)[source]

Test that a single MeterMeasurement dumped to JSON can be recovered correctly.

test.test_MeterMeasure.test_meter_measurement_returns_empty(initialized_measurement_frame)[source]

A MeterMeasurement with no data added must return True on is_empty() method.