# test_with_pytest.py import pytest from mock import patch from cnf.config import Config from cnf.config_read_json import ConfigReadJson from cnf.config_read_toml import ConfigReadToml from test_config import ConfigDefault, ConfigComplete class CnfIfc(ConfigReadJson): def __init__(self): pass class FakeBuffer: rd = str() wr = str() test_buffer = FakeBuffer class FakeFile(): def __init__(self): self.buf = test_buffer def __enter__(self): return self def __exit__(self, exc_type, exc, tb): pass class FakeOptionsFile(FakeFile): def __init__(self, OpenTextMode): super().__init__() self.bin_mode = 'b' in OpenTextMode def read(self): print(f"Fake.read: bmode:{self.bin_mode}") if self.bin_mode: return bytearray(self.buf.rd.encode('utf-8')).copy() else: print(f"Fake.read: str:{self.buf.rd}") return self.buf.rd def patch_open(): def new_open(file: str, OpenTextMode="r"): if file == "_no__file__no_": raise FileNotFoundError return FakeOptionsFile(OpenTextMode) with patch('builtins.open', new_open) as conn: yield conn @pytest.fixture def ConfigTomlEmpty(): return { 'mqtt': {'host': 'mqtt', 'port': 1883, 'user': '', 'passwd': ''}, 'ha': {'auto_conf_prefix': 'homeassistant', 'discovery_prefix': 'homeassistant', 'entity_prefix': 'tsun', 'proxy_node_id': 'proxy', 'proxy_unique_id': 'P170000000000001'}, 'solarman': { 'enabled': True, 'host': 'iot.talent-monitoring.com', 'port': 10000, }, 'tsun': { 'enabled': True, 'host': 'logger.talent-monitoring.com', 'port': 5005, }, 'inverters': { 'allow_all': False }, 'gen3plus': {'at_acl': {'tsun': {'allow': [], 'block': []}, 'mqtt': {'allow': [], 'block': []}}}, } def test_no_config(ConfigDefault): test_buffer.rd = "" # empty buffer, no json Config.init(ConfigReadToml("app/src/cnf/default_config.toml")) for _ in patch_open(): ConfigReadJson() err = Config.get_error() assert err == 'error: Expecting value: line 1 column 1 (char 0)' cnf = Config.get() assert cnf == ConfigDefault def test_no_file(ConfigDefault): test_buffer.rd = "" # empty buffer, no json Config.init(ConfigReadToml("app/src/cnf/default_config.toml")) for _ in patch_open(): ConfigReadJson("_no__file__no_") err = Config.get_error() assert err == None cnf = Config.get() assert cnf == ConfigDefault def test_invalid_filename(ConfigDefault): test_buffer.rd = "" # empty buffer, no json Config.init(ConfigReadToml("app/src/cnf/default_config.toml")) for _ in patch_open(): ConfigReadJson(None) err = Config.get_error() assert err == None cnf = Config.get() assert cnf == ConfigDefault def test_cnv1(): """test dotted key converting""" tst = { "gen3plus.at_acl.mqtt.block": [ "AT+SUPDATE", "AT+" ] } cnf = ConfigReadJson() obj = cnf.convert_to_obj(tst) assert obj == { 'gen3plus': { 'at_acl': { 'mqtt': { 'block': [ 'AT+SUPDATE', "AT+" ], }, }, }, } def test_cnv2(): """test a valid list with serials in inverters""" tst = { "inverters": [ { "serial": "R170000000000001", }, { "serial": "Y170000000000001", } ], } cnf = ConfigReadJson() obj = cnf.convert_to_obj(tst) assert obj == { 'inverters': { 'R170000000000001': {}, 'Y170000000000001': {} }, } def test_cnv3(): """test the combination of a list and a scalar in inverters""" tst = { "inverters": [ { "serial": "R170000000000001", }, { "serial": "Y170000000000001", } ], "inverters.allow_all": False, } cnf = ConfigReadJson() obj = cnf.convert_to_obj(tst) assert obj == { 'inverters': { 'R170000000000001': {}, 'Y170000000000001': {}, 'allow_all': False, }, } def test_cnv4(): tst = { "inverters": [ { "serial": "R170000000000001", "node_id": "PV-Garage/", "suggested_area": "Garage", "modbus_polling": False, "pv1.manufacturer": "man1", "pv1.type": "type1", "pv2.manufacturer": "man2", "pv2.type": "type2", "sensor_list": 688 }, { "serial": "Y170000000000001", "monitor_sn": 2000000000, "node_id": "PV-Garage2/", "suggested_area": "Garage2", "modbus_polling": True, "client_mode.host": "InverterIP", "client_mode.port": 1234, "client_mode.forward": True, "pv1.manufacturer": "man1", "pv1.type": "type1", "pv2.manufacturer": "man2", "pv2.type": "type2", "pv3.manufacturer": "man3", "pv3.type": "type3", "pv4.manufacturer": "man4", "pv4.type": "type4", "sensor_list": 688 } ], "tsun.enabled": True, "solarman.enabled": True, "inverters.allow_all": False, "gen3plus.at_acl.tsun.allow": [ "AT+Z", "AT+UPURL", "AT+SUPDATE" ], "gen3plus.at_acl.tsun.block": [ "AT+SUPDATE" ], "gen3plus.at_acl.mqtt.allow": [ "AT+" ], "gen3plus.at_acl.mqtt.block": [ "AT+SUPDATE" ] } cnf = ConfigReadJson() obj = cnf.convert_to_obj(tst) assert obj == { 'gen3plus': {'at_acl': {'mqtt': {'allow': ['AT+'], 'block': ['AT+SUPDATE']}, 'tsun': {'allow': ['AT+Z', 'AT+UPURL', 'AT+SUPDATE'], 'block': ['AT+SUPDATE']}}}, 'inverters': {'R170000000000001': {'modbus_polling': False, 'node_id': 'PV-Garage/', 'pv1': { 'manufacturer': 'man1', 'type': 'type1'}, 'pv2': { 'manufacturer': 'man2', 'type': 'type2'}, 'sensor_list': 688, 'suggested_area': 'Garage'}, 'Y170000000000001': {'client_mode': { 'host': 'InverterIP', 'port': 1234, 'forward': True}, 'modbus_polling': True, 'monitor_sn': 2000000000, 'node_id': 'PV-Garage2/', 'pv1': { 'manufacturer': 'man1', 'type': 'type1'}, 'pv2': { 'manufacturer': 'man2', 'type': 'type2'}, 'pv3': { 'manufacturer': 'man3', 'type': 'type3'}, 'pv4': { 'manufacturer': 'man4', 'type': 'type4'}, 'sensor_list': 688, 'suggested_area': 'Garage2'}, 'allow_all': False}, 'solarman': {'enabled': True}, 'tsun': {'enabled': True} } def test_cnv5(): """test a invalid list with missing serials""" tst = { "inverters": [ { "node_id": "PV-Garage1/", }, { "serial": "Y170000000000001", "node_id": "PV-Garage2/", } ], } cnf = ConfigReadJson() obj = cnf.convert_to_obj(tst) assert obj == { 'inverters': { 'Y170000000000001': {'node_id': 'PV-Garage2/'} }, } def test_cnv6(): """test overwritting a value in inverters""" tst = { "inverters": [{ "serial": "Y170000000000001", "node_id": "PV-Garage2/", }], } tst2 = { "inverters": [{ "serial": "Y170000000000001", "node_id": "PV-Garden/", }], } cnf = ConfigReadJson() conf = {} for key, val in tst.items(): cnf.convert_inv_arr(conf, key, val) assert conf == { 'inverters': { 'Y170000000000001': {'node_id': 'PV-Garage2/'} }, } for key, val in tst2.items(): cnf.convert_inv_arr(conf, key, val) assert conf == { 'inverters': { 'Y170000000000001': {'node_id': 'PV-Garden/'} }, } def test_empty_config(ConfigDefault): test_buffer.rd = "{}" # empty json Config.init(ConfigReadToml("app/src/cnf/default_config.toml")) for _ in patch_open(): ConfigReadJson() err = Config.get_error() assert err == None cnf = Config.get() assert cnf == ConfigDefault def test_full_config(ConfigComplete): test_buffer.rd = """ { "inverters": [ { "serial": "R170000000000001", "node_id": "PV-Garage/", "suggested_area": "Garage", "modbus_polling": false, "pv1.manufacturer": "man1", "pv1.type": "type1", "pv2.manufacturer": "man2", "pv2.type": "type2", "sensor_list": 688 }, { "serial": "Y170000000000001", "monitor_sn": 2000000000, "node_id": "PV-Garage2/", "suggested_area": "Garage2", "modbus_polling": true, "pv1.manufacturer": "man1", "pv1.type": "type1", "pv2.manufacturer": "man2", "pv2.type": "type2", "pv3.manufacturer": "man3", "pv3.type": "type3", "pv4.manufacturer": "man4", "pv4.type": "type4", "sensor_list": 688 }, { "serial": "Y170000000000002", "monitor_sn": 2000000001, "modbus_polling": false, "modbus_scanning.start": 2048, "node_id": "PV-Garage3", "suggested_area": "Garage3", "sensor_list": 688 } ], "batteries": [ { "serial": "4100000000000001", "modbus_polling": true, "monitor_sn": 3000000000, "node_id": "Bat-Garage3", "suggested_area": "Garage3", "pv1.manufacturer": "man5", "pv1.type": "type5", "pv2.manufacturer": "man6", "pv2.type": "type6", "sensor_list": 12326 } ], "tsun.enabled": true, "solarman.enabled": true, "inverters.allow_all": false, "gen3plus.at_acl.tsun.allow": [ "AT+Z", "AT+UPURL", "AT+SUPDATE" ], "gen3plus.at_acl.tsun.block": [ "AT+SUPDATE" ], "gen3plus.at_acl.mqtt.allow": [ "AT+" ], "gen3plus.at_acl.mqtt.block": [ "AT+SUPDATE" ] } """ Config.init(ConfigReadToml("app/src/cnf/default_config.toml")) for _ in patch_open(): ConfigReadJson() err = Config.get_error() assert err == None cnf = Config.get() assert cnf == ConfigComplete