示例#1
0
    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
示例#2
0
def db_connection():
    models = [ClubUser, ClubMessage]
    db = SqliteDatabase(':memory:')
    with db:
        db.bind(models)
        db.create_tables(models)
        yield db
        db.drop_tables(models)
示例#3
0
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)
示例#5
0
def db_connection():
    models = [Metric]
    db = SqliteDatabase(':memory:')
    with db:
        db.bind(models)
        db.create_tables(models)
        yield db
        db.drop_tables(models)
示例#6
0
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)
示例#7
0
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())
示例#8
0
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)
示例#9
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)
示例#10
0
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()
示例#11
0
 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()
示例#12
0
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()
示例#13
0
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()
示例#14
0
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()
示例#15
0
 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()
示例#16
0
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()
示例#18
0
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)
示例#19
0
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)
        )
示例#20
0
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)
示例#21
0
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)
示例#22
0
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())
示例#24
0
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])
示例#25
0
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',
示例#26
0
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
示例#27
0
 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])
示例#28
0
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])
示例#29
0
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))