def create(cls, db_name, db_type, host=None, user=None, password=None, port=5432, models=_MODELS): """ Setup ORM.""" if db_type == 'sqlite': logger.info(F'Opening connection to sqlite') db = SqliteDatabase(db_name, pragmas={ 'journal_mode': 'wal', 'cache_size': -1 * 64000, # 64MB 'foreign_keys': 1, 'ignore_check_constraints': 0, } ) elif db_type == 'postgres': db = PostgresqlDatabase(db_name, user=user, password=password, host=host, port=port, autoconnect=True) else: logger.error(F'Unknown database type {db_type}') raise ValueError db.bind(models) db.create_tables(models, safe=True) cls._db_handle = db cls._db_name = db_name cls._db_models = models
def db_connection(): models = [ClubUser, ClubMessage] db = SqliteDatabase(':memory:') with db: db.bind(models) db.create_tables(models) yield db db.drop_tables(models)
def init_db(filename: str = ":memory:") -> SqliteDatabase: """ Bind an SQLite database to the Peewee ORM models. """ db = SqliteDatabase(filename) db.bind(BaseModel.model_registry) db.create_tables(BaseModel.model_registry) return db
def db_connection(): models = [Event, EventSpeaking, MessageAuthor] db = SqliteDatabase(':memory:') with db: db.bind(models) db.create_tables(models) yield db db.drop_tables(models)
def db_connection(): models = [Metric] db = SqliteDatabase(':memory:') with db: db.bind(models) db.create_tables(models) yield db db.drop_tables(models)
class ValveDriverTest(unittest.TestCase): @classmethod def setUpClass(cls): fakesleep.monkey_patch() SetTestMode() @classmethod def tearDownClass(cls): fakesleep.monkey_restore() def setUp(self): self.test_db = SqliteDatabase(':memory:') self.test_db.bind(MODELS) self.test_db.connect() self.test_db.create_tables(MODELS) def tearDown(self): self.test_db.drop_tables(MODELS) self.test_db.close() def test_valve_driver(self): valve_output_1 = Output.create(number=2) valve_1 = Valve.create(number=1, name='valve 1', delay=30, output=valve_output_1) SetUpTestInjections(output_controller=mock.Mock(OutputController)) driver_1 = ValveDriver(valve_1) self.assertEqual(valve_1.id, driver_1.id) self.assertEqual(0, driver_1.percentage) self.assertEqual(0, driver_1._desired_percentage) self.assertFalse(driver_1.is_open) self.assertFalse(driver_1.in_transition) driver_1.set(50) self.assertEqual(50, driver_1._desired_percentage) driver_1.close() self.assertEqual(0, driver_1._desired_percentage) driver_1.open() self.assertEqual(100, driver_1._desired_percentage) self.assertTrue(driver_1.will_open) driver_1.steer_output() driver_1._output_controller.set_output_status.assert_called_once() self.assertFalse(driver_1.will_open) self.assertEqual(100, driver_1.percentage) self.assertFalse(driver_1.is_open) self.assertTrue(driver_1.in_transition) time.sleep(20) self.assertFalse(driver_1.is_open) self.assertTrue(driver_1.in_transition) time.sleep(15) self.assertTrue(driver_1.is_open) self.assertFalse(driver_1.in_transition)
def _jobs(sample_sheet, data_file): "Verify job configuration by actually running them on sample data, through their submitter." # create an in-mem database from peewee import SqliteDatabase db = SqliteDatabase(":memory:", pragmas={'foreign_keys': 1}, autoconnect=False) db.bind(models.REGISTRY, bind_refs=True, bind_backrefs=True) db.connect() db.create_tables(models.REGISTRY) from porerefiner.config import Config Config['nanopore']['path'] = data_file.parent # create a run ru = Run.create(name=data_file.parent.name, ended=datetime.datetime.now(), status='DONE', path=data_file.parent) # load the sample sheet # save the sample to the run with open(sample_sheet, 'rb') as sheet: ss = SampleSheet.new_sheet_from_message(sheet=( samplesheets.load_from_csv, samplesheets.load_from_excel)['xslx' in sample_sheet.name](sheet), run=ru) with open(data_file, 'rb') as data: hash = hashlib.md5() hash.update(data.read()) md5 = hash.hexdigest() # create a file and add it to the run fi = models.File.create( path=data_file, run=ru, checksum=md5, ) async def fileJob(job): j = fi.spawn(job) await jobs.submit_job(j) while j.status not in ('DONE', 'FAILED'): await jobs.poll_active_job(j) async def runJob(job): j = ru.spawn(job) await jobs.submit_job(j) while j.status not in ('DONE', 'FAILED'): await jobs.poll_active_job(j) async def task(): await gather(*[fileJob(job) for job in jobs.JOBS.FILES] + [runJob(job) for job in jobs.JOBS.RUNS]) run(task())
def database(): """ Setup the test database. """ test_db = SqliteDatabase(':memory:') test_db.bind([Message, HasTapped], bind_refs=False, bind_backrefs=False) test_db.connect() test_db.create_tables([Message, HasTapped]) HasTapped.create(has_tapped=0)
class PumpDriverTest(unittest.TestCase): @classmethod def setUpClass(cls): SetTestMode() def setUp(self): self.test_db = SqliteDatabase(':memory:') self.test_db.bind(MODELS) self.test_db.connect() self.test_db.create_tables(MODELS) def tearDown(self): self.test_db.drop_tables(MODELS) self.test_db.close() def test_pump_driver(self): output = Output.create(number=0) pump = Pump.create(number=1, name='pump', output=output) SetUpTestInjections(output_controller=mock.Mock(OutputController)) driver = PumpDriver(pump) self.assertIsNone(driver.state) self.assertFalse(driver.error) self.assertEqual(pump.id, driver.id) driver.turn_on() self.assertTrue(driver.state) self.assertFalse(driver.error) driver.turn_off() self.assertFalse(driver.state) self.assertFalse(driver.error) driver._output_controller.set_output_status.side_effect = RuntimeError() with self.assertRaises(RuntimeError): driver.turn_on() self.assertFalse(driver.state) self.assertTrue(driver.error) driver._output_controller.set_output_status.side_effect = None driver.turn_on() self.assertTrue(driver.state) self.assertFalse(driver.error) driver._output_controller.set_output_status.side_effect = RuntimeError() with self.assertRaises(RuntimeError): driver.turn_off() self.assertTrue(driver.state) self.assertTrue(driver.error) driver._output_controller.set_output_status.side_effect = None driver.turn_off() self.assertFalse(driver.state) self.assertFalse(driver.error)
def db_in_memory(): """Binds all models to in-memory SQLite and creates all tables`""" db = SqliteDatabase(':memory:') db.bind(ALL_MODELS) db.connect() db.create_tables(ALL_MODELS) yield db db.drop_tables(ALL_MODELS) db.close()
def wrapped_test_function(*a, **k): db = SqliteDatabase(":memory:", pragmas={'foreign_keys': 1}, autoconnect=False) db.bind(models.REGISTRY, bind_refs=True, bind_backrefs=True) db.connect() db.create_tables(models.REGISTRY) try: return func(*a, **k) finally: db.drop_tables(models.REGISTRY) db.close()
class TestBase(TestCase): def setUp(self): self.db = SqliteDatabase(":memory:", pragmas={'foreign_keys': 1}, autoconnect=False) self.db.bind(models.REGISTRY, bind_refs=False, bind_backrefs=False) self.db.connect() self.db.create_tables(models.REGISTRY) def tearDown(self): #[cls.delete().where(True).execute() for cls in models.REGISTRY] self.db.drop_tables(models.REGISTRY) self.db.close()
async def test_plugins(config_path): "Suite to test your configured plugins." if not Path(config_path).exists(): raise click.BadParameter(f"No config file at {config_path}.") from porerefiner.config import Config config = Config(config_path) # monkey-patch the subprocess runners plugins usually use # so we can intercept output and exit codes import subprocess, asyncio _run = subprocess.run _a_exec = asyncio.create_subprocess_exec _a_shell = asyncio.create_subprocess_shell def instrumented_run(*args, **kwargs): kwargs['capture_output'] = True proc = _run(*args, **kwargs) click.echo(proc.stdout) if proc.returncode: # prompt user if subprocess call failed; for testing purposes they can usually ignore this click.echo(proc.stderr) if click.confirm("Subprocess ended with non-zero exit code. Ignore failure?"): proc.returncode = 0 return proc async def instrumented_exec(_a_sub, *args, **kwargs): kwargs['stdout'] = asyncio.subprocess.PIPE kwargs['stderr'] = asyncio.subprocess.PIPE proc = await _a_sub(*args, **kwargs) stdout, stderr = await proc.communicate() click.echo(stdout) if proc.returncode: click.echo(stderr) if click.confirm("Subprocess ended with non-zero exit code. Ignore failure?"): proc.returncode = 0 return proc subprocess.run = instrumented_run asyncio.create_subprocess_exec = partial(instrumented_exec, _a_sub=_a_exec) asyncio.create_subprocess_shell = partial(instrumented_exec, _a_sub=_a_shell) # Start up the job system with an in-memory database from peewee import SqliteDatabase from porerefiner import models, jobs, submitters db = SqliteDatabase(":memory:", pragmas={'foreign_keys':1}, autoconnect=False) db.bind(models.REGISTRY, bind_refs=False, bind_backrefs=False) db.connect() db.create_tables(models.REGISTRY) # Create a fake run run = models.Run()
class BaseTestCase(unittest.TestCase): """Base class for testing DB.""" def setUp(self): """Set up database.""" super(BaseTestCase, self).setUp() self.conn = SqliteDatabase(":memory:") self.conn.bind(MODELS, bind_refs=False, bind_backrefs=False) self.conn.connect() self.conn.create_tables(MODELS) def tearDown(self): """Cleanup database.""" self.conn.drop_tables(MODELS) self.conn.close()
def l(loop): logging.basicConfig(stream=open('/dev/null', 'w')) db = SqliteDatabase(":memory:", pragmas={'foreign_keys': 1}, autoconnect=False) db.bind(models.REGISTRY, bind_refs=False, bind_backrefs=False) db.connect() db.create_tables(models.REGISTRY) asyncio.set_event_loop(loop) loop.run_forever() click.echo( f"{models.Run.select().count()} runs, {models.File.select().count()} files" ) db.drop_tables(models.REGISTRY) db.close()
class DB: def __init__(self, tmpdir): self.db = SqliteDatabase(os.path.join(tmpdir, 'bills_test.db')) self.db.bind(MODELS) self.db.connect() self.db.create_tables(MODELS) self.db.close() def connect(self): self.db.connect() def close(self): self.db.close() def drop_tables(self): self.db.drop_tables(MODELS)
class DBTestCase(unittest.TestCase): def setUp(self): # use an in-memory SQLite for tests. self.test_db = SqliteDatabase(':memory:', pragmas={'foreign_keys': 1}) # Bind model classes to test db. Since we have a complete list of # all models, we do not need to recursively bind dependencies. self.test_db.bind(MODELS, bind_refs=False, bind_backrefs=False) self.test_db.connect() self.test_db.create_tables(MODELS) def tearDown(self): # Not strictly necessary since SQLite in-memory databases only live # for the duration of the connection, and in the next step we close # the connection...but a good practice all the same. self.test_db.drop_tables(MODELS) # Close connection to db. self.test_db.close()
class PumpValveControllerTest(unittest.TestCase): @classmethod def setUpClass(cls): fakesleep.monkey_patch() SetTestMode() logger = logging.getLogger('openmotics') logger.setLevel(logging.DEBUG) logger.propagate = False handler = logging.StreamHandler() handler.setLevel(logging.DEBUG) handler.setFormatter( logging.Formatter( "%(asctime)s - %(name)s - %(levelname)s - %(message)s")) logger.addHandler(handler) @classmethod def tearDownClass(cls): fakesleep.monkey_restore() def setUp(self): self.test_db = SqliteDatabase(':memory:') self.test_db.bind(MODELS) self.test_db.connect() self.test_db.create_tables(MODELS) self._gateway_api = mock.Mock(GatewayApi) self._gateway_api.get_sensor_temperature_status.return_value = 0.0 self._pump_valve_controller = mock.Mock(PumpValveController) SetUpTestInjections(gateway_api=self._gateway_api) self._thermostat_group = ThermostatGroup.create( number=0, name='thermostat group', on=True, threshold_temperature=10.0, sensor=Sensor.create(number=1), mode='heating') def tearDown(self): self.test_db.drop_tables(MODELS) self.test_db.close() def _get_thermostat_pid(self): thermostat = Thermostat.create(number=1, name='thermostat 1', sensor=Sensor.create(number=10), pid_heating_p=200, pid_heating_i=100, pid_heating_d=50, pid_cooling_p=200, pid_cooling_i=100, pid_cooling_d=50, automatic=True, room=None, start=0, valve_config='equal', thermostat_group=self._thermostat_group) ValveToThermostat.create(thermostat=thermostat, valve=Valve.create( number=1, name='valve 1', output=Output.create(number=1)), mode=ThermostatGroup.Modes.HEATING, priority=0) ValveToThermostat.create(thermostat=thermostat, valve=Valve.create( number=2, name='valve 2', output=Output.create(number=2)), mode=ThermostatGroup.Modes.COOLING, priority=0) Preset.create(type=Preset.Types.SCHEDULE, heating_setpoint=20.0, cooling_setpoint=25.0, active=True, thermostat=thermostat) return ThermostatPid(thermostat=thermostat, pump_valve_controller=self._pump_valve_controller) def test_basic(self): thermostat_pid = self._get_thermostat_pid() self.assertEqual([1, 2], thermostat_pid.valve_ids) self.assertEqual([1], thermostat_pid._heating_valve_ids) self.assertEqual([2], thermostat_pid._cooling_valve_ids) self.assertEqual(200, thermostat_pid.kp) self.assertEqual(100, thermostat_pid.ki) self.assertEqual(50, thermostat_pid.kd) def test_enabled(self): thermostat_pid = self._get_thermostat_pid() self.assertTrue(thermostat_pid.enabled) # No sensor configured sensor = thermostat_pid._thermostat.sensor thermostat_pid._thermostat.sensor = None self.assertFalse(thermostat_pid.enabled) thermostat_pid._thermostat.sensor = sensor self.assertTrue(thermostat_pid.enabled) # No valves heating_valve_ids = thermostat_pid._heating_valve_ids thermostat_pid._heating_valve_ids = [] thermostat_pid._cooling_valve_ids = [] self.assertFalse(thermostat_pid.enabled) thermostat_pid._heating_valve_ids = heating_valve_ids self.assertTrue(thermostat_pid.enabled) # The group is turned off self._thermostat_group.on = False self.assertFalse(thermostat_pid.enabled) self._thermostat_group.on = True self.assertTrue(thermostat_pid.enabled) # A high amount of errors thermostat_pid._errors = 10 self.assertFalse(thermostat_pid.enabled) thermostat_pid._errors = 0 self.assertTrue(thermostat_pid.enabled) def test_tick(self): thermostat_pid = self._get_thermostat_pid() thermostat_pid._pid = mock.Mock(PID) thermostat_pid._pid.setpoint = 0.0 self.assertTrue(thermostat_pid.enabled) self._thermostat_group.on = False self._pump_valve_controller.set_valves.call_count = 0 self._pump_valve_controller.set_valves.mock_calls = [] self.assertFalse(thermostat_pid.tick()) self._pump_valve_controller.steer.assert_called_once() self.assertEqual( sorted([ mock.call(0, [1], mode='equal'), mock.call(0, [2], mode='equal') ]), sorted(self._pump_valve_controller.set_valves.mock_calls)) self.assertEqual(2, self._pump_valve_controller.set_valves.call_count) self._thermostat_group.on = True for mode, output_power, heating_power, cooling_power in [ (ThermostatGroup.Modes.HEATING, 100, 100, 0), (ThermostatGroup.Modes.HEATING, 50, 50, 0), (ThermostatGroup.Modes.HEATING, 0, 0, 0), (ThermostatGroup.Modes.HEATING, -50, 0, 0), (ThermostatGroup.Modes.COOLING, -100, 0, 100), (ThermostatGroup.Modes.COOLING, -50, 0, 50), (ThermostatGroup.Modes.COOLING, 0, 0, 0), (ThermostatGroup.Modes.COOLING, 50, 0, 0) ]: thermostat_pid._mode = mode thermostat_pid._pid.return_value = output_power self._pump_valve_controller.steer.call_count = 0 self._pump_valve_controller.set_valves.call_count = 0 self._pump_valve_controller.set_valves.mock_calls = [] self.assertTrue(thermostat_pid.tick()) self._pump_valve_controller.steer.assert_called_once() self.assertEqual( sorted([ mock.call(heating_power, [1], mode='equal'), mock.call(cooling_power, [2], mode='equal') ]), sorted(self._pump_valve_controller.set_valves.mock_calls)) self.assertEqual(2, self._pump_valve_controller.set_valves.call_count)
class MsgDb: def __init__(self, name, sql_dir = 'db/'): self.name = str(name) self.SQL_DIR = sql_dir # 连接数据库 db_name = '{:s}.db'.format(self.name) path = os.path.join(self.SQL_DIR, db_name) self.db = SqliteDatabase(path, pragmas=( ('cache_size', -1024 * 64), # 64MB page-cache. ('journal_mode', 'wal'))) # Use WAL-mode (you should always use this!). self.db.connect() self.db.bind(MODELS) self.db.create_tables(MODELS) def close(self): self.db.close() def __user_medal(self, msg): ''' 格式化信息中的牌子 ''' if msg['cmd'] == 'DANMU_MSG': if msg['info'][3]: if msg['info'][3][11] == 1: return { 'n': msg['info'][3][1], #牌子名 'l': msg['info'][3][0], #牌子等级 'c': msg['info'][3][10], #舰长类别 } else: if msg['data']['medal_info']: if msg['data']['medal_info']['is_lighted'] == 1: return { 'n': msg['data']['medal_info']['medal_name'], #牌子名 'l': msg['data']['medal_info']['medal_level'], #牌子等级 'c': msg['data']['medal_info']['guard_level'], #舰长类别 } return { 'n': None, #牌子名 'l': None, #牌子等级 'c': None #舰长类别 } def __insert_msg(self, msg, insert_list): ''' 向列表插入一条信息 识别并格式化 ''' if msg['cmd'] == 'DANMU_MSG': medal = self.__user_medal(msg) insert_list[msg['cmd']].append({ 'captain': medal['c'], #舰长类别 'content': msg['info'][1], #弹幕文本 'medal_level': medal['l'], #牌子等级 'medal_name': medal['n'], #牌子名 'timestamp': msg['info'][0][4], #时间戳 'uid': msg['info'][2][0], #用户id 'username': msg['info'][2][1], #用户名 }) elif msg['cmd'] == 'SEND_GIFT': medal = self.__user_medal(msg) insert_list[msg['cmd']].append({ 'captain': medal['c'], #舰长类别 'gift_coin_type': msg['data']['coin_type'], #货币类型 'gift_name': msg['data']['giftName'], #礼物名 'gift_num': msg['data']['num'], #礼物数量 'gift_price': msg['data']['price'], #礼物单价 'gift_total_price': msg['data']['total_coin'], #礼物总价 'medal_level': medal['l'], #牌子等级 'medal_name': medal['n'], #牌子名 'timestamp': msg['data']['timestamp']*1000, #时间戳 'uid': msg['data']['uid'], #用户id 'username': msg['data']['uname'], #用户名 }) elif msg['cmd'] == 'USER_TOAST_MSG': insert_list[msg['cmd']].append({ 'captain': msg['data']['guard_level'], #大航海类别 'captain_num': msg['data']['num'], #数量 'captain_total_price': msg['data']['price'], #真实花费价格(RMB) 'timestamp': msg['data']['start_time']*1000, #时间戳 'uid': msg['data']['uid'], #用户id 'username': msg['data']['username'], #用户名 }) elif msg['cmd'] == 'SUPER_CHAT_MESSAGE': medal = self.__user_medal(msg) insert_list[msg['cmd']].append({ 'captain': medal['c'], #舰长类别 'medal_level': medal['l'], #牌子等级 'medal_name': medal['n'], #牌子名 'superchat_content': msg['data']['message'], #醒目留言文本 'superchat_price': msg['data']['price'], #价格(RMB) 'timestamp': msg['data']['ts']*1000, #时间戳 'uid': msg['data']['uid'], #用户id 'username': msg['data']['user_info']['uname'], #用户名 }) elif msg['cmd'] == 'VIEW': insert_list[msg['cmd']].append({ 'timestamp': msg['timestamp'], #时间戳 'view': msg['data'], #人气值 }) elif msg['cmd'] == 'WATCHED_CHANGE': insert_list[msg['cmd']].append({ 'timestamp': msg['timestamp'], #时间戳 'watched': msg['data']['num'], #看过的人数 }) else: return None def commit_msgs(self, msgs): ''' 向数据库提交信息列表 ''' # 绑定model self.db.bind(MODELS) # 列表分类 insert_list = {} for t in MSG_TYPE: insert_list[t] = [] # 创建插入列表 for msg in msgs: self.__insert_msg(msg, insert_list) # 插入数据 with self.db.atomic(): Danmu.insert_many(insert_list['DANMU_MSG']).execute() Gift.insert_many(insert_list['SEND_GIFT']).execute() Captain.insert_many(insert_list['USER_TOAST_MSG']).execute() SuperChat.insert_many(insert_list['SUPER_CHAT_MESSAGE']).execute() View.insert_many(insert_list['VIEW']).execute() WatchedChange.insert_many(insert_list['WATCHED_CHANGE']).execute() def live_action(self, timestamp, action): ''' 向数据库提交直播状态(开始、结束) ''' # 绑定model self.db.bind(MODELS) # 插入数据 LiveStatus.insert(timestamp=timestamp, action=action).execute() def get_live_time(self, date): ''' date为datetime.date对象 获取当天直播开始和结束时间列表 将北京时间第一天4:00到第二天4:00作为分界线 若不存在,则返回[[None, None]] ''' t = datetime.time(4, 0, 0, 0) start_t = datetime.datetime.combine(date, t) dt = datetime.timedelta(days=1) time_range = [int(start_t.timestamp()*1000), int((start_t+dt).timestamp()*1000)] data = (LiveStatus .select() .where(LiveStatus.timestamp>=time_range[0], LiveStatus.timestamp<=time_range[1]) .order_by(LiveStatus.timestamp)) if len(data) == 0: return [[None, None]] # 核心逻辑: # 第一个判断是start还是end,end就把开头设为start # 最后一个判断是start还是end,是start且边界在当前时间之前(说明不是没播完)就把结尾设为end # 上一个是start,下一个就去找end,如果是start就无视掉,反之同理 action_list = list(data.dicts()) if action_list[0]["action"] == "end": action_list.insert(0, {"action": "start", "timestamp": time_range[0]}) if action_list[-1]["action"] == "start" and time_range[1]<time.time()*1000: action_list.append({"action": "end", "timestamp": time_range[1]}) rst = [] last = "end" for d in action_list: if d["action"] == last: continue if d["action"] == "start": rst.append([d["timestamp"], None]) last = "start" elif d["action"] == "end": rst[-1][1] = d["timestamp"] last = "end" # 筛选每个时间段 太短(小于1min)不要 rst_filtered = [] for x in rst: if x[-1] != None: if x[1]-x[0]<60*1000: continue rst_filtered.append(x) return rst_filtered def query_table_on_live(self, model, date, idx): ''' 取出当天在开播时间段内的一个表格 若没有结束时间就到最新的为止 date为datetime.date对象 idx为直播次序编号 ''' start, end = self.get_live_time(date)[idx] # 如果没有结束时间就持续到下一天4点 if end == None: dt = datetime.timedelta(days=1) end = int(datetime.datetime.combine(date+dt, datetime.time(4, 0, 0, 0)).timestamp()*1000) # 绑定model self.db.bind(MODELS) data = None if start: if end: data = model.select().where(model.timestamp >= start, model.timestamp <= end).dicts() else: data = model.select().where(model.timestamp >= start).dicts() return list(data) def query_msg(self, date, idx): ''' 取出本数据库在开播时间段内的所有弹幕和sc date为datetime.date对象 idx为今天直播次序编号 从0开始 ''' return ( self.query_table_on_live(Danmu, date, idx), self.query_table_on_live(SuperChat, date, idx) )
class PumpValveControllerTest(unittest.TestCase): @classmethod def setUpClass(cls): fakesleep.monkey_patch() SetTestMode() logger = logging.getLogger('openmotics') logger.setLevel(logging.DEBUG) logger.propagate = False handler = logging.StreamHandler() handler.setLevel(logging.DEBUG) handler.setFormatter( logging.Formatter( "%(asctime)s - %(name)s - %(levelname)s - %(message)s")) logger.addHandler(handler) @classmethod def tearDownClass(cls): fakesleep.monkey_restore() def setUp(self): self.test_db = SqliteDatabase(':memory:') self.test_db.bind(MODELS) self.test_db.connect() self.test_db.create_tables(MODELS) def tearDown(self): self.test_db.drop_tables(MODELS) self.test_db.close() def test_open_valves(self): Valve.create(number=1, name='valve 1', delay=30, output=Output.create(number=1)) Valve.create(number=2, name='valve 2', delay=30, output=Output.create(number=2)) Valve.create(number=3, name='valve 3', delay=30, output=Output.create(number=3)) SetUpTestInjections(output_controller=mock.Mock(OutputController)) controller = PumpValveController() controller.refresh_from_db() self.assertIn(1, controller._valve_drivers) valve_driver_1 = controller.get_valve_driver(1) self.assertIn(2, controller._valve_drivers) valve_driver_2 = controller.get_valve_driver(2) self.assertIn(3, controller._valve_drivers) valve_driver_3 = controller.get_valve_driver(3) for percentage, mode, results in [(100, 'equal', [100, 100]), (50, 'equal', [50, 50]), (0, 'equal', [0, 0]), (100, 'cascade', [100, 100]), (75, 'cascade', [100, 50]), (50, 'cascade', [100, 0]), (0, 'cascade', [0, 0])]: controller.set_valves(percentage, [1, 2], mode) self.assertEqual(results[0], valve_driver_1._desired_percentage) self.assertEqual(results[1], valve_driver_2._desired_percentage) self.assertEqual(0, valve_driver_3._desired_percentage) def test_transitions(self): pump_1 = Pump.create(number=1, name='pump 1', output=Output.create(number=1)) pump_2 = Pump.create(number=2, name='pump 2', output=Output.create(number=2)) valve_1 = Valve.create(number=1, name='valve 1', delay=30, output=Output.create(number=11)) valve_2 = Valve.create(number=2, name='valve 2', delay=15, output=Output.create(number=12)) valve_3 = Valve.create(number=3, name='valve 3', delay=15, output=Output.create(number=13)) PumpToValve.create(pump=pump_1, valve=valve_1) PumpToValve.create(pump=pump_1, valve=valve_2) PumpToValve.create(pump=pump_2, valve=valve_3) SetUpTestInjections(output_controller=mock.Mock(OutputController)) controller = PumpValveController() controller.refresh_from_db() valve_driver_1 = controller.get_valve_driver(1) valve_driver_2 = controller.get_valve_driver(2) valve_driver_3 = controller.get_valve_driver(3) pump_driver_1 = controller._pump_drivers[1] pump_driver_2 = controller._pump_drivers[2] # Initial state, everything is off self.assertFalse(pump_driver_1.state) self.assertEqual(0, valve_driver_1.percentage) self.assertEqual(0, valve_driver_2.percentage) self.assertFalse(pump_driver_2.state) self.assertEqual(0, valve_driver_3.percentage) # Set the second valve to 50% # The pump should only be turned on after 15s valve_driver_2.set(50) controller.steer() self.assertFalse(pump_driver_1.state) self.assertEqual(0, valve_driver_1.percentage) self.assertEqual(50, valve_driver_2.percentage) self.assertFalse(pump_driver_2.state) self.assertEqual(0, valve_driver_3.percentage) # Pump still off after 10s time.sleep(10) controller.steer() self.assertFalse(pump_driver_1.state) self.assertEqual(0, valve_driver_1.percentage) self.assertEqual(50, valve_driver_2.percentage) self.assertFalse(pump_driver_2.state) self.assertEqual(0, valve_driver_3.percentage) # Pump is on after 10s time.sleep(10) controller.steer() self.assertTrue(pump_driver_1.state) self.assertEqual(0, valve_driver_1.percentage) self.assertEqual(50, valve_driver_2.percentage) self.assertFalse(pump_driver_2.state) self.assertEqual(0, valve_driver_3.percentage) # Other valves are also opened valve_driver_1.set(100) valve_driver_3.set(100) controller.steer() self.assertTrue(pump_driver_1.state) self.assertEqual(100, valve_driver_1.percentage) self.assertEqual(50, valve_driver_2.percentage) self.assertFalse(pump_driver_2.state) self.assertEqual(100, valve_driver_3.percentage) # After a time, both valves are fully open time.sleep(40) controller.steer() self.assertTrue(pump_driver_1.state) self.assertEqual(100, valve_driver_1.percentage) self.assertEqual(50, valve_driver_2.percentage) self.assertTrue(pump_driver_2.state) self.assertEqual(100, valve_driver_3.percentage) # Two valves are closed again # When valves are closed, the pumps are stopped immediately valve_driver_2.set(0) valve_driver_3.set(0) time.sleep(10) controller.steer() self.assertTrue(pump_driver_1.state) self.assertEqual(100, valve_driver_1.percentage) self.assertEqual(0, valve_driver_2.percentage) self.assertFalse(pump_driver_2.state) self.assertEqual(0, valve_driver_3.percentage)
from peewee import SqliteDatabase import os from src.models.ad import Ad models = [ Ad, ] if 'ADREG_TEST_DB' in os.environ: database = SqliteDatabase(os.getenv('ADREG_TEST_DB')) else: database = SqliteDatabase('adreg.db') database.bind(models) database.create_tables(models)
def setup_test_db(): test_db = SqliteDatabase(":memory:") test_db.bind(MODELS) test_db.connect() test_db.create_tables(MODELS)
class ThermostatControllerTest(unittest.TestCase): @classmethod def setUpClass(cls): fakesleep.monkey_patch() SetTestMode() logger = logging.getLogger('openmotics') logger.setLevel(logging.DEBUG) logger.propagate = False handler = logging.StreamHandler() handler.setLevel(logging.DEBUG) handler.setFormatter(logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")) logger.addHandler(handler) @classmethod def tearDownClass(cls): fakesleep.monkey_restore() def setUp(self): self.test_db = SqliteDatabase(':memory:') self.test_db.bind(MODELS) self.test_db.connect() self.test_db.create_tables(MODELS) self._gateway_api = mock.Mock(GatewayApi) self._gateway_api.get_timezone.return_value = 'Europe/Brussels' self._gateway_api.get_sensor_temperature_status.return_value = 10.0 output_controller = mock.Mock(OutputController) output_controller.get_output_status.return_value = OutputStateDTO(id=0, status=False) SetUpTestInjections(gateway_api=self._gateway_api, output_controller=output_controller, pubsub=mock.Mock()) self._thermostat_controller = ThermostatControllerGateway() SetUpTestInjections(thermostat_controller=self._thermostat_controller) self._thermostat_group = ThermostatGroup.create(number=0, name='thermostat group', on=True, threshold_temperature=10.0, sensor=Sensor.create(number=1), mode='heating') def tearDown(self): self.test_db.drop_tables(MODELS) self.test_db.close() def test_save_pumpgroups(self): thermostat = Thermostat.create(number=1, name='thermostat 1', sensor=Sensor.create(number=10), pid_heating_p=200, pid_heating_i=100, pid_heating_d=50, pid_cooling_p=200, pid_cooling_i=100, pid_cooling_d=50, automatic=True, room=None, start=0, valve_config='equal', thermostat_group=self._thermostat_group) valve_1_output = Output.create(number=1) valve_1 = Valve.create(number=1, name='valve 1', output=valve_1_output) valve_2_output = Output.create(number=2) valve_2 = Valve.create(number=2, name='valve 2', output=valve_2_output) valve_3_output = Output.create(number=3) valve_3 = Valve.create(number=3, name='valve 3', output=valve_3_output) ValveToThermostat.create(thermostat=thermostat, valve=valve_1, mode=ThermostatGroup.Modes.HEATING, priority=0) ValveToThermostat.create(thermostat=thermostat, valve=valve_2, mode=ThermostatGroup.Modes.COOLING, priority=0) ValveToThermostat.create(thermostat=thermostat, valve=valve_3, mode=ThermostatGroup.Modes.HEATING, priority=0) Preset.create(type=Preset.Types.SCHEDULE, heating_setpoint=20.0, cooling_setpoint=25.0, active=True, thermostat=thermostat) pump_output = Output.create(number=4) pump = Pump.create(name='pump 1', output=pump_output) heating_pump_groups = self._thermostat_controller.load_heating_pump_groups() self.assertEqual([PumpGroupDTO(id=pump.id, pump_output_id=pump_output.id, valve_output_ids=[], room_id=None)], heating_pump_groups) PumpToValve.create(pump=pump, valve=valve_1) PumpToValve.create(pump=pump, valve=valve_2) pump_groups = self._thermostat_controller.load_heating_pump_groups() self.assertEqual([PumpGroupDTO(id=pump.id, pump_output_id=pump_output.id, valve_output_ids=[valve_1_output.id], room_id=None)], pump_groups) pump_groups = self._thermostat_controller.load_cooling_pump_groups() self.assertEqual([PumpGroupDTO(id=pump.id, pump_output_id=pump_output.id, valve_output_ids=[valve_2_output.id], room_id=None)], pump_groups) self._thermostat_controller._save_pump_groups(ThermostatGroup.Modes.HEATING, [(PumpGroupDTO(id=pump.id, pump_output_id=pump_output.id, valve_output_ids=[valve_1_output.id, valve_3_output.id]), ['pump_output_id', 'valve_output_ids'])]) pump_groups = self._thermostat_controller.load_heating_pump_groups() self.assertEqual([PumpGroupDTO(id=pump.id, pump_output_id=pump_output.id, valve_output_ids=[valve_1_output.id, valve_3_output.id], room_id=None)], pump_groups) pump_groups = self._thermostat_controller.load_cooling_pump_groups() self.assertEqual([PumpGroupDTO(id=pump.id, pump_output_id=pump_output.id, valve_output_ids=[valve_2_output.id], room_id=None)], pump_groups) def test_thermostat_group_crud(self): thermostat = Thermostat.create(number=1, name='thermostat 1', sensor=Sensor.create(number=10), pid_heating_p=200, pid_heating_i=100, pid_heating_d=50, pid_cooling_p=200, pid_cooling_i=100, pid_cooling_d=50, automatic=True, room=None, start=0, valve_config='equal', thermostat_group=self._thermostat_group) Output.create(number=1) Output.create(number=2) Output.create(number=3) valve_output = Output.create(number=4) valve = Valve.create(number=1, name='valve 1', output=valve_output) ValveToThermostat.create(thermostat=thermostat, valve=valve, mode=ThermostatGroup.Modes.HEATING, priority=0) thermostat_group = ThermostatGroup.get(number=0) # type: ThermostatGroup self.assertEqual(10.0, thermostat_group.threshold_temperature) self.assertEqual(0, OutputToThermostatGroup.select() .where(OutputToThermostatGroup.thermostat_group == thermostat_group) .count()) self._thermostat_controller.save_thermostat_group((ThermostatGroupDTO(id=0, outside_sensor_id=1, pump_delay=30, threshold_temperature=15, switch_to_heating_0=(1, 0), switch_to_heating_1=(2, 100), switch_to_cooling_0=(1, 100)), ['outside_sensor_id', 'pump_delay', 'threshold_temperature', 'switch_to_heating_0', 'switch_to_heating_1', 'switch_to_cooling_0'])) thermostat_group = ThermostatGroup.get(number=0) self.assertEqual(15.0, thermostat_group.threshold_temperature) links = [{'index': link.index, 'value': link.value, 'mode': link.mode, 'output': link.output_id} for link in (OutputToThermostatGroup.select() .where(OutputToThermostatGroup.thermostat_group == thermostat_group))] self.assertEqual(3, len(links)) self.assertIn({'index': 0, 'value': 0, 'mode': 'heating', 'output': 1}, links) self.assertIn({'index': 1, 'value': 100, 'mode': 'heating', 'output': 2}, links) self.assertIn({'index': 0, 'value': 100, 'mode': 'cooling', 'output': 1}, links) new_thermostat_group_dto = ThermostatGroupDTO(id=0, outside_sensor_id=1, pump_delay=60, threshold_temperature=10, switch_to_heating_0=(1, 50), switch_to_cooling_0=(2, 0)) self._thermostat_controller.save_thermostat_group((new_thermostat_group_dto, ['outside_sensor_id', 'pump_delay', 'threshold_temperature', 'switch_to_heating_0', 'switch_to_heating_1', 'switch_to_cooling_0'])) thermostat_group = ThermostatGroup.get(number=0) self.assertEqual(10.0, thermostat_group.threshold_temperature) links = [{'index': link.index, 'value': link.value, 'mode': link.mode, 'output': link.output_id} for link in (OutputToThermostatGroup.select() .where(OutputToThermostatGroup.thermostat_group == thermostat_group))] self.assertEqual(2, len(links)) self.assertIn({'index': 0, 'value': 50, 'mode': 'heating', 'output': 1}, links) self.assertIn({'index': 0, 'value': 0, 'mode': 'cooling', 'output': 2}, links) self.assertEqual(new_thermostat_group_dto, self._thermostat_controller.load_thermostat_group()) def test_thermostat_control(self): thermostat = Thermostat.create(number=1, name='thermostat 1', sensor=Sensor.create(number=10), pid_heating_p=200, pid_heating_i=100, pid_heating_d=50, pid_cooling_p=200, pid_cooling_i=100, pid_cooling_d=50, automatic=True, room=None, start=0, valve_config='equal', thermostat_group=self._thermostat_group) Output.create(number=1) Output.create(number=2) Output.create(number=3) valve_output = Output.create(number=4) valve = Valve.create(number=1, name='valve 1', output=valve_output) ValveToThermostat.create(thermostat=thermostat, valve=valve, mode=ThermostatGroup.Modes.HEATING, priority=0) self._thermostat_controller.refresh_config_from_db() expected = ThermostatGroupStatusDTO(id=0, on=True, setpoint=0, cooling=False, automatic=True, statusses=[ThermostatStatusDTO(id=1, name='thermostat 1', automatic=True, setpoint=0, sensor_id=10, actual_temperature=10.0, setpoint_temperature=14.0, outside_temperature=10.0, output_0_level=0, output_1_level=0, mode=0, airco=0)]) self.assertEqual(expected, self._thermostat_controller.get_thermostat_status()) self._thermostat_controller.set_current_setpoint(thermostat_number=1, heating_temperature=15.0) expected.statusses[0].setpoint_temperature = 15.0 self.assertEqual(expected, self._thermostat_controller.get_thermostat_status()) self._thermostat_controller.set_per_thermostat_mode(thermostat_number=1, automatic=True, setpoint=16.0) expected.statusses[0].setpoint_temperature = 16.0 self.assertEqual(expected, self._thermostat_controller.get_thermostat_status()) preset = self._thermostat_controller.get_current_preset(thermostat_number=1) self.assertTrue(preset.active) self.assertEqual(30.0, preset.cooling_setpoint) self.assertEqual(16.0, preset.heating_setpoint) self.assertEqual(Preset.Types.SCHEDULE, preset.type) self._thermostat_controller.set_current_preset(thermostat_number=1, preset_type=Preset.Types.PARTY) expected.statusses[0].setpoint_temperature = 14.0 expected.statusses[0].setpoint = expected.setpoint = 5 # PARTY = legacy `5` setpoint expected.statusses[0].automatic = expected.automatic = False self.assertEqual(expected, self._thermostat_controller.get_thermostat_status()) self._thermostat_controller.set_thermostat_mode(thermostat_on=True, cooling_mode=True, cooling_on=True, automatic=False, setpoint=4) expected.statusses[0].setpoint_temperature = 30.0 expected.statusses[0].setpoint = expected.setpoint = 4 # VACATION = legacy `4` setpoint expected.cooling = True self.assertEqual(expected, self._thermostat_controller.get_thermostat_status()) self._thermostat_controller.set_thermostat_mode(thermostat_on=True, cooling_mode=False, cooling_on=True, automatic=True) expected.statusses[0].setpoint_temperature = 16.0 expected.statusses[0].setpoint = expected.setpoint = 0 # AUTO = legacy `0/1/2` setpoint expected.statusses[0].automatic = expected.automatic = True expected.cooling = False self.assertEqual(expected, self._thermostat_controller.get_thermostat_status())
def init_peewee_database(collection_old_db_path): # TODO: write tests for this directory = os.path.dirname(collection_old_db_path) database = SqliteDatabase(os.path.join(directory, 'collection_new.sqlite3')) database.bind([NoteType, RevisionAnswer])
from constants import MODELS, DATETIME_FORMAT, LOCAL_TIMEZONE from model import AuthorizedUser, PromoCodeGroup, PromoCode from utils import (validate_group_name, parse_codes_in_bulk, validate_code, sqlite_datetime_hack, send_long_message_array) load_dotenv() BOT_TOKEN = os.getenv('BOT_TOKEN') SENTRY_URL = os.getenv('SENTRY_URL') SENTRY_ENVIRONMENT = os.getenv('SENTRY_ENVIRONMENT', 'unknown') bot = commands.Bot(command_prefix='$') db = SqliteDatabase('database.sqlite', pragmas={'foreign_keys': 1}) db.bind(MODELS) db.create_tables(MODELS) sentry_sdk.init(SENTRY_URL, traces_sample_rate=1.0, environment=SENTRY_ENVIRONMENT) @bot.event async def on_ready(): logging.info('Logged on as %s!', bot.user) @bot.event async def on_command_error(ctx, error): sentry_sdk.add_breadcrumb(category='discord.command_name',
def test_database(): test_db = SqliteDatabase(":memory:") test_db.bind([Message, User], bind_refs=False, bind_backrefs=False) test_db.connect() test_db.create_tables([Message, User]) return test_db
def inner(models_list): database = SqliteDatabase(os.environ['ADREG_TEST_DB']) database.bind(models_list) return dict([(model.__name__, model) for model in models_list])
from db_declaration import Danmu, LiveStatus, Gift, SuperChat, Captain, View, WatchedChange from peewee import SqliteDatabase path = "../db/8792912.db" #path = "db/22384516.db" db = SqliteDatabase( path, pragmas=( ('cache_size', -1024 * 64), # 64MB page-cache. ('journal_mode', 'wal'))) # Use WAL-mode (you should always use this!). db.connect() db.bind([Danmu, LiveStatus, Gift, SuperChat, Captain, View, WatchedChange]) db.create_tables( [Danmu, LiveStatus, Gift, SuperChat, Captain, View, WatchedChange])
class PluginControllerTest(unittest.TestCase): """ Tests for the PluginController. """ PLUGINS_PATH = None PLUGIN_CONFIG_PATH = None RUNTIME_PATH = os.path.dirname(plugin_runtime.__file__) @classmethod def setUpClass(cls): SetTestMode() cls.PLUGINS_PATH = tempfile.mkdtemp() cls.PLUGIN_CONFIG_PATH = tempfile.mkdtemp() logger = logging.getLogger('openmotics') logger.setLevel(logging.DEBUG) logger.propagate = False handler = logging.StreamHandler() handler.setLevel(logging.DEBUG) handler.setFormatter( logging.Formatter( "%(asctime)s - %(name)s - %(levelname)s - %(message)s")) logger.addHandler(handler) def setUp(self): self.test_db = SqliteDatabase(':memory:') self.test_db.bind(MODELS) self.test_db.connect() self.test_db.create_tables(MODELS) def tearDown(self): self.test_db.drop_tables(MODELS) self.test_db.close() @classmethod def tearDownClass(cls): try: if cls.PLUGINS_PATH is not None: shutil.rmtree(cls.PLUGINS_PATH) if cls.PLUGIN_CONFIG_PATH is not None: shutil.rmtree(cls.PLUGIN_CONFIG_PATH) except Exception: pass @staticmethod def _create_plugin(name, code, base_path=None): """ Create a plugin with a given name and the provided code. """ if base_path is None: base_path = PluginControllerTest.PLUGINS_PATH path = '{0}/{1}'.format(base_path, name) os.makedirs(path) with open('{0}/main.py'.format(path), 'w') as code_file: code_file.write(code) with open('{0}/__init__.py'.format(path), 'w'): pass @staticmethod def _destroy_plugin(name): """ Remove the code for a plugin created by _create_plugin. """ path = '{0}/{1}'.format(PluginControllerTest.PLUGINS_PATH, name) if os.path.exists(path): shutil.rmtree(path) @staticmethod def _get_controller(output_controller=None, shutter_controller=None): SetUpTestInjections(shutter_controller=shutter_controller, web_interface=None, configuration_controller=None, output_controller=output_controller) from plugins.base import PluginController PluginController.DEPENDENCIES_TIMER = 0.25 controller = PluginController( runtime_path=PluginControllerTest.RUNTIME_PATH, plugins_path=PluginControllerTest.PLUGINS_PATH, plugin_config_path=PluginControllerTest.PLUGIN_CONFIG_PATH) metric_controller = type( 'MetricController', (), { 'get_filter': lambda *args, **kwargs: ['test'], 'set_plugin_definitions': lambda _self, *args, **kwargs: None })() controller.set_metrics_controller(metric_controller) return controller @staticmethod def _create_plugin_package(name, code): temp_directory = tempfile.mkdtemp() try: PluginControllerTest._create_plugin(name, code, temp_directory) call('cd {0}/{1}; tar -czf ../package.tgz .'.format( temp_directory, name), shell=True) with open('{0}/package.tgz'.format(temp_directory), 'rb') as package_file: package_data = package_file.read() hasher = hashlib.md5() hasher.update(package_data) calculated_md5 = hasher.hexdigest() return calculated_md5, package_data finally: shutil.rmtree(temp_directory) @mark.slow def test_get_one_plugin(self): """ Test getting one plugin in the plugins package. """ controller = None try: PluginControllerTest._create_plugin( 'P1', """ from plugins.base import * class P1(OMPluginBase): name = 'P1' version = '1.0.0' interfaces = [] """) controller = PluginControllerTest._get_controller() controller.start() plugin_list = controller.get_plugins() self.assertEqual(1, len(plugin_list)) self.assertEqual('P1', plugin_list[0].name) plugin = Plugin.get(name='P1') self.assertEqual('1.0.0', plugin.version) finally: if controller is not None: controller.stop() PluginControllerTest._destroy_plugin('P1') @mark.slow def test_get_two_plugins(self): """ Test getting two plugins in the plugins package. """ controller = None try: PluginControllerTest._create_plugin( 'P1', """ from plugins.base import * class P1(OMPluginBase): name = 'P1' version = '1.0.0' interfaces = [] """) PluginControllerTest._create_plugin( 'P2', """ from plugins.base import * class P2(OMPluginBase): name = 'P2' version = '1.0.0' interfaces = [] """) controller = PluginControllerTest._get_controller() controller.start() plugin_list = controller.get_plugins() self.assertEqual(2, len(plugin_list)) names = sorted([plugin_list[0].name, plugin_list[1].name]) self.assertEqual(['P1', 'P2'], names) finally: if controller is not None: controller.stop() PluginControllerTest._destroy_plugin('P1') PluginControllerTest._destroy_plugin('P2') @mark.slow def test_dependencies_callback(self): """ Test getting one plugin in the plugins package. """ called = {'called': 0} def _call(): called['called'] += 1 def _wait_for_called(amount, timeout=1): end = time.time() + timeout while time.time() < end: if called['called'] == amount: break self.assertEqual(amount, called['called']) controller = None try: PluginControllerTest._create_plugin( 'P1', """ from plugins.base import * class P1(OMPluginBase): name = 'P1' version = '1.0.0' interfaces = [] """) controller = PluginControllerTest._get_controller() controller._update_dependencies = _call controller.start() self.assertIsNotNone(controller._dependencies_timer) self.assertEquals(0, called['called']) _wait_for_called(1) controller.stop_plugin('P1') _wait_for_called(2) finally: if controller is not None: controller.stop() PluginControllerTest._destroy_plugin('P1') @mark.slow def test_get_special_methods(self): """ Test getting special methods on a plugin. """ controller = None try: PluginControllerTest._create_plugin( 'P1', """ import time from plugins.base import * class P1(OMPluginBase): name = 'P1' version = '0.1.0' interfaces = [('webui', '1.0')] def __init__(self, webservice, logger): OMPluginBase.__init__(self, webservice, logger) self._bg_running = False self._input_data = None self._input_data_version_2 = None self._output_data = None self._output_data_version_2 = None self._event_data = None @om_expose(auth=True) def html_index(self): return 'HTML' @om_expose(auth=False) def get_log(self): return {'bg_running': self._bg_running, 'input_data': self._input_data, 'input_data_version_2': self._input_data_version_2, 'output_data': self._output_data, 'output_data_version_2': self._output_data_version_2, 'event_data': self._event_data} @input_status def input(self, input_status_inst): self._input_data = input_status_inst @input_status(version=2) def input_version_2(self, input_status_inst): self._input_data_version_2 = input_status_inst @output_status def output(self, output_status_inst): self._output_data = output_status_inst @output_status(version=2) def output_version_2(self, output_status_inst): self._output_data_version_2 = output_status_inst @receive_events def recv_events(self, code): self._event_data = code @background_task def run(self): while True: self._bg_running = True time.sleep(1) """) output_controller = Mock(OutputController) output_controller.get_output_statuses = lambda: [ OutputStateDTO(id=1, status=True, dimmer=5) ] controller = PluginControllerTest._get_controller( output_controller=output_controller) controller.start() response = controller._request('P1', 'html_index') self.assertEqual(response, 'HTML') rising_input_event = { 'id': 1, 'status': True, 'location': { 'room_id': 1 } } controller.process_observer_event( GatewayEvent(event_type=GatewayEvent.Types.INPUT_CHANGE, data=rising_input_event)) falling_input_event = { 'id': 2, 'status': False, 'location': { 'room_id': 5 } } controller.process_observer_event( GatewayEvent(event_type=GatewayEvent.Types.INPUT_CHANGE, data=falling_input_event)) output_event = { 'id': 1, 'status': { 'on': True, 'value': 5, 'locked': True }, 'location': { 'room_id': 5 } } controller.process_observer_event( GatewayEvent(event_type=GatewayEvent.Types.OUTPUT_CHANGE, data=output_event)) controller.process_event(1) keys = [ 'input_data', 'input_data_version_2', 'output_data', 'output_data_version_2', 'event_data' ] start = time.time() while time.time() - start < 2: response = controller._request('P1', 'get_log') if all(response[key] is not None for key in keys): break time.sleep(0.1) self.assertEqual(response['bg_running'], True) self.assertEqual( response['input_data'], [1, None]) # only rising edges should be triggered self.assertEqual(response['output_data'], [[1, 5]]) self.assertEqual(response['output_data_version_2'], output_event) self.assertEqual(response['event_data'], 1) finally: if controller is not None: controller.stop() PluginControllerTest._destroy_plugin('P1') @mark.slow def test_get_unsupported_decorators(self): """ Test getting special methods on a plugin. """ controller = None try: PluginControllerTest._create_plugin( 'UnsupportedPlugin', """ import time from plugins.base import * class UnsupportedPlugin(OMPluginBase): name = 'UnsupportedPlugin' version = '0.1.0' interfaces = [('webui', '1.0')] def __init__(self, webservice, logger): OMPluginBase.__init__(self, webservice, logger) @om_expose(auth=True) def html_index(self): return 'HTML' @input_status(version=3) def input_with_unsupported_decorator(self, test_data): pass @output_status(version=3) def output_with_unsupported_decorator(self, test_data): pass """) output_controller = Mock(OutputController) controller = PluginControllerTest._get_controller( output_controller=output_controller) # the plugin will fail to load, but only log this controller.start() # get the logs and check if we see the output in the logs plugin_logs = controller.get_logs()['UnsupportedPlugin'] matches = ['Decorator', 'version', 'is not supported'] self.assertTrue(all(match in plugin_logs for match in matches), plugin_logs) finally: if controller is not None: controller.stop() PluginControllerTest._destroy_plugin('UnsupportedPlugin') @mark.slow def test_get_shutter_decorators(self): """ Test getting shutter decorators on a plugin. """ controller = None try: PluginControllerTest._create_plugin( 'ShutterPlugin', """ from plugins.base import * class ShutterPlugin(OMPluginBase): name = 'ShutterPlugin' version = '0.1.0' interfaces = [('webui', '1.0')] def __init__(self, webservice, logger): OMPluginBase.__init__(self, webservice, logger) self._shutter_data_v1 = None self._shutter_data_v1_detail = None self._shutter_data_v2 = None self._shutter_data_v3 = None @om_expose(auth=True) def html_index(self): return 'HTML' @om_expose(auth=False) def get_log(self): return {'shutter_data_v1': self._shutter_data_v1, 'shutter_data_v1_detail': self._shutter_data_v1_detail, 'shutter_data_v2': self._shutter_data_v2, 'shutter_data_v3': self._shutter_data_v3} @shutter_status def shutter_v1(self, test_data): self._shutter_data_v1 = test_data @shutter_status def shutter_v1_detail(self, test_data, detail): self._shutter_data_v1_detail = (test_data, detail) @shutter_status(version=2) def shutter_v2(self, test_data, detail): self._shutter_data_v2 = (test_data, detail) @shutter_status(version=3) def shutter_v3(self, shutter_event): self._shutter_data_v3 = shutter_event """) shutter_controller = Mock(ShutterController) shutter_status = [ShutterEnums.State.STOPPED] detail_for_shutter = { 1: { 'state': ShutterEnums.State.STOPPED, 'actual_position': None, 'desired_position': None, 'last_change': 1596787761.147892 } } shutter_controller.get_states = lambda: { 'status': shutter_status, 'detail': detail_for_shutter } controller = PluginControllerTest._get_controller( shutter_controller=shutter_controller) controller.start() shutter_event = GatewayEvent( event_type=GatewayEvent.Types.SHUTTER_CHANGE, data={'some_random_key': 'some_random_value'}) controller.process_observer_event(shutter_event) keys = [ 'shutter_data_v1', 'shutter_data_v1_detail', 'shutter_data_v2', 'shutter_data_v3' ] start = time.time() response = None while time.time() - start < 2: response = controller._request('ShutterPlugin', 'get_log') if all(response[key] is not None for key in keys): break time.sleep(0.1) self.maxDiff = None self.assertEqual(response['shutter_data_v1'], shutter_status) self.assertEqual(response['shutter_data_v1_detail'], [shutter_status, detail_for_shutter]) self.assertEqual(response['shutter_data_v2'], [shutter_status, detail_for_shutter]) self.assertEqual(response['shutter_data_v3'], shutter_event.data) finally: if controller is not None: controller.stop() PluginControllerTest._destroy_plugin('ShutterPlugin') @mark.slow def test_update_plugin(self): """ Validates whether a plugin can be updated """ test_1_md5, test_1_data = PluginControllerTest._create_plugin_package( 'Test', """ from plugins.base import * class Test(OMPluginBase): name = 'Test' version = '0.0.1' interfaces = [] """) test_2_md5, test_2_data = PluginControllerTest._create_plugin_package( 'Test', """ from plugins.base import * class Test(OMPluginBase): name = 'Test' version = '0.0.2' interfaces = [] """) controller = PluginControllerTest._get_controller() controller.start() # Install first version result = controller.install_plugin(test_1_md5, test_1_data) self.assertEqual(result, 'Plugin successfully installed') controller.start_plugin('Test') self.assertEqual([r.name for r in controller.get_plugins()], ['Test']) plugin = Plugin.get(name='Test') self.assertEqual('0.0.1', plugin.version) # Update to version 2 result = controller.install_plugin(test_2_md5, test_2_data) self.assertEqual(result, 'Plugin successfully installed') self.assertEqual([r.name for r in controller.get_plugins()], ['Test']) plugin = Plugin.get(name='Test') self.assertEqual('0.0.2', plugin.version) @mark.slow def test_plugin_metric_reference(self): """ Validates whether two plugins won't get the same metric instance """ controller = None try: p1_md5, p1_data = PluginControllerTest._create_plugin_package( 'P1', """ from plugins.base import * class P1(OMPluginBase): name = 'P1' version = '0.0.1' interfaces = [] def __init__(self, webservice, logger): OMPluginBase.__init__(self, webservice, logger) self._metric = None @om_expose(auth=False) def get_metric(self): return {'metric': self._metric} @om_metric_receive() def set_metric(self, metric): self._metric = metric self._metric['foo'] = 'P1' """) p2_md5, p2_data = PluginControllerTest._create_plugin_package( 'P2', """ from plugins.base import * class P2(OMPluginBase): name = 'P2' version = '0.0.1' interfaces = [] def __init__(self, webservice, logger): OMPluginBase.__init__(self, webservice, logger) self._metric = None @om_expose(auth=False) def get_metric(self): return {'metric': self._metric} @om_metric_receive() def set_metric(self, metric): self._metric = metric self._metric['foo'] = 'P2' """) controller = PluginControllerTest._get_controller() controller.start() controller.install_plugin(p1_md5, p1_data) controller.start_plugin('P1') controller.install_plugin(p2_md5, p2_data) controller.start_plugin('P2') delivery_rate = controller.distribute_metrics([{ 'timestamp': 0, 'source': 'test', 'type': 'test', 'tags': {}, 'values': {} }]) self.assertEqual({'total': 2, 'test.test': 2}, delivery_rate) start = time.time() p1_metric = {'metric': None} p2_metric = {'metric': None} while time.time() - start < 2: p1_metric = controller._request('P1', 'get_metric') p2_metric = controller._request('P2', 'get_metric') if p1_metric['metric'] is not None and p2_metric[ 'metric'] is not None: break time.sleep(0.1) self.assertIsNotNone(p1_metric['metric']) self.assertEqual('P1', p1_metric['metric'].get('foo')) self.assertIsNotNone(p2_metric['metric']) self.assertEqual('P2', p2_metric['metric'].get('foo')) # Compare the addresses to make sure it's a different instance self.assertNotEqual(id(p1_metric['metric']), id(p2_metric['metric'])) finally: if controller is not None: controller.stop() PluginControllerTest._destroy_plugin('P1') PluginControllerTest._destroy_plugin('P2') def test_check_plugin(self): """ Test the exception that can occur when checking a plugin. """ from plugin_runtime.utils import check_plugin from plugin_runtime.base import OMPluginBase PluginControllerTest._get_controller() class P1(OMPluginBase): """ Plugin without name. """ pass try: check_plugin(P1) except PluginException as exception: self.assertEqual( 'Attribute \'name\' is missing from the plugin class', str(exception)) class P2(OMPluginBase): """ Plugin with malformed name. """ name = 'malformed name' try: check_plugin(P2) except PluginException as exception: self.assertEqual( 'Plugin name \'malformed name\' is malformed: can only contain letters, numbers and underscores.', str(exception)) class P3(OMPluginBase): """ Plugin without version. """ name = 'test_name123' try: check_plugin(P3) except PluginException as exception: self.assertEqual( 'Attribute \'version\' is missing from the plugin class', str(exception)) class P4(OMPluginBase): """ Plugin without interfaces. """ name = 'test' version = '1.0.0' try: check_plugin(P4) except PluginException as exception: self.assertEqual( 'Attribute \'interfaces\' is missing from the plugin class', str(exception)) class P5(OMPluginBase): """ Valid plugin. """ name = 'test' version = '1.0.0' interfaces = [] check_plugin(P5) class P6(OMPluginBase): """ Plugin that violates the webui interface. """ name = 'test' version = '1.0.0' interfaces = [('webui', '1.0')] try: check_plugin(P6) except PluginException as exception: self.assertEqual( 'Plugin \'test\' has no method named \'html_index\'', str(exception))