Beispiel #1
0
 def testStarOptionOn(self, _priv_check):
     c = Client()
     c.force_login(self.u2)
     some_limit = 100
     sql_with_star = 'select * from some_table'
     some_db = 'some_db'
     _priv_check.return_value = {
         'status': 0,
         'data': {
             'limit_num': 100,
             'priv_check': 1
         }
     }
     archer_config = SysConfig()
     archer_config.set('disable_star', True)
     r = c.post('/query/',
                data={
                    'instance_name': self.slave1.instance_name,
                    'sql_content': sql_with_star,
                    'db_name': some_db,
                    'limit_num': some_limit
                })
     archer_config.set('disable_star', False)
     r_json = r.json()
     self.assertEqual(1, r_json['status'])
Beispiel #2
0
 def tearDown(self):
     archer_config = SysConfig()
     archer_config.set('mail_smtp_server', '')
     archer_config.set('mail_smtp_user', '')
     archer_config.set('mail_smtp_password', '')
     archer_config.set('mail_smtp_port', '')
     archer_config.set('mail_ssl', '')
Beispiel #3
0
 def test_purge(self):
     archer_config = SysConfig()
     archer_config.set('some_key', 'some_value')
     archer_config.purge()
     self.assertEqual({}, archer_config.sys_config)
     archer_config2 = SysConfig()
     self.assertEqual({}, archer_config2.sys_config)
Beispiel #4
0
 def setUp(self):
     self.username = '******'
     self.password = '******'
     self.u1 = User(username=self.username, password=self.password, display='用户1')
     self.u1.save()
     self.resource_group1 = ResourceGroup.objects.create(group_name='some_group')
     sys_config = SysConfig()
     sys_config.set('default_resource_group', self.resource_group1.group_name)
Beispiel #5
0
 def tearDown(self):
     self.u1.delete()
     self.u2.delete()
     self.slave1.delete()
     self.query_apply_1.delete()
     QueryPrivileges.objects.all().delete()
     archer_config = SysConfig()
     archer_config.set('disable_star', False)
Beispiel #6
0
 def setUp(self):
     """
     创建默认组给注册关联用户, 打开注册
     """
     archer_config = SysConfig()
     archer_config.set('sign_up_enabled', 'true')
     archer_config.get_all_config()
     self.client = Client()
     Group.objects.create(id=1, name='默认组')
Beispiel #7
0
 def testSenderInit(self):
     sender = MsgSender()
     self.assertEqual(sender.MAIL_REVIEW_SMTP_PORT, self.smtp_port)
     archer_config = SysConfig()
     archer_config.set('mail_smtp_port', '')
     sender = MsgSender()
     self.assertEqual(sender.MAIL_REVIEW_SMTP_PORT, 465)
     archer_config.set('mail_ssl', False)
     sender = MsgSender()
     self.assertEqual(sender.MAIL_REVIEW_SMTP_PORT, 25)
Beispiel #8
0
 def testSSLSendMail(self, _quit, sendmail, login, _):
     """SSL 测试"""
     some_sub = 'test_subject'
     some_body = 'mail_body'
     some_to = ['mail_to']
     archer_config = SysConfig()
     archer_config.set('mail_ssl', True)
     sender = MsgSender()
     sender.send_email(some_sub, some_body, some_to)
     sendmail.assert_called_with(self.smtp_user, some_to, ANY)
     _quit.assert_called_once()
Beispiel #9
0
    def testNoPasswordSendMail(self, _quit, sendmail, login, _):
        """无密码测试"""
        some_sub = 'test_subject'
        some_body = 'mail_body'
        some_to = ['mail_to']
        archer_config = SysConfig()
        archer_config.set('mail_ssl', '')

        archer_config.set('mail_smtp_password', '')
        sender2 = MsgSender()
        sender2.send_email(some_sub, some_body, some_to)
        login.assert_not_called()
Beispiel #10
0
 def setUp(self):
     archer_config = SysConfig()
     self.smtp_server = 'test_smtp_server'
     self.smtp_user = '******'
     self.smtp_password = '******'
     self.smtp_port = 1234
     self.smtp_ssl = True
     archer_config.set('mail_smtp_server', self.smtp_server)
     archer_config.set('mail_smtp_user', self.smtp_user)
     archer_config.set('mail_smtp_password', self.smtp_password)
     archer_config.set('mail_smtp_port', self.smtp_port)
     archer_config.set('mail_ssl', self.smtp_ssl)
Beispiel #11
0
class TestSchemaSync(TestCase):
    """
    测试SchemaSync
    """
    def setUp(self):
        self.superuser = User(username='******', is_superuser=True)
        self.superuser.save()
        # 使用 travis.ci 时实例和测试service保持一致
        self.master = Instance(
            instance_name='test_instance',
            type='master',
            db_type='mysql',
            host=settings.DATABASES['default']['HOST'],
            port=settings.DATABASES['default']['PORT'],
            user=settings.DATABASES['default']['USER'],
            password=settings.DATABASES['default']['PASSWORD'])
        self.master.save()
        self.sys_config = SysConfig()
        self.client = Client()
        self.client.force_login(self.superuser)

    def tearDown(self):
        self.superuser.delete()
        self.master.delete()
        self.sys_config.replace(json.dumps({}))

    def test_schema_sync(self):
        """
        测试SchemaSync
        :return:
        """
        data = {
            "instance_name": "test_instance",
            "db_name": "*",
            "target_instance_name": "test_instance",
            "target_db_name": "*",
            "sync_auto_inc": True,
            "sync_comments": False
        }
        r = self.client.post(path='/instance/schemasync/', data=data)
        self.assertEqual(json.loads(r.content)['status'], 1)
        self.assertEqual(json.loads(r.content)['msg'], '请配置SchemaSync路径!')
        self.sys_config.set('schemasync',
                            '/opt/venv4schemasync/bin/schemasync')
        self.sys_config.get_all_config()
        r = self.client.post(path='/instance/schemasync/', data=data)
        self.assertEqual(json.loads(r.content)['status'], 0)
Beispiel #12
0
class TestOracle(TestCase):
    """Oracle 测试"""

    def setUp(self):
        self.ins = Instance.objects.create(instance_name='some_ins', type='slave', db_type='oracle',
                                           host='some_host', port=3306, user='******', password='******',
                                           sid='some_id')
        self.wf = SqlWorkflow.objects.create(
            workflow_name='some_name',
            group_id=1,
            group_name='g1',
            engineer_display='',
            audit_auth_groups='some_group',
            create_time=datetime.now() - timedelta(days=1),
            status='workflow_finish',
            is_backup=True,
            instance=self.ins,
            db_name='some_db',
            syntax_type=1
        )
        SqlWorkflowContent.objects.create(workflow=self.wf)
        self.sys_config = SysConfig()

    def tearDown(self):
        self.ins.delete()
        SqlWorkflow.objects.all().delete()
        SqlWorkflowContent.objects.all().delete()

    @patch('cx_Oracle.makedsn')
    @patch('cx_Oracle.connect')
    def test_get_connection(self, _connect, _makedsn):
        # 填写 sid 测试
        new_engine = OracleEngine(self.ins)
        new_engine.get_connection()
        _connect.assert_called_once()
        _makedsn.assert_called_once()
        # 填写 service_name 测试
        _connect.reset_mock()
        _makedsn.reset_mock()
        self.ins.service_name = 'some_service'
        self.ins.sid = ''
        self.ins.save()
        new_engine = OracleEngine(self.ins)
        new_engine.get_connection()
        _connect.assert_called_once()
        _makedsn.assert_called_once()
        # 都不填写, 检测 ValueError
        _connect.reset_mock()
        _makedsn.reset_mock()
        self.ins.service_name = ''
        self.ins.sid = ''
        self.ins.save()
        new_engine = OracleEngine(self.ins)
        with self.assertRaises(ValueError):
            new_engine.get_connection()

    @patch('cx_Oracle.connect.cursor.execute')
    @patch('cx_Oracle.connect.cursor')
    @patch('cx_Oracle.connect')
    def test_query(self, _conn, _cursor, _execute):
        _conn.return_value.cursor.return_value.fetchmany.return_value = [(1,)]
        new_engine = OracleEngine(instance=self.ins)
        query_result = new_engine.query(db_name=0, sql='select 1', limit_num=100)
        self.assertIsInstance(query_result, ResultSet)
        self.assertListEqual(query_result.rows, [(1,)])

    @patch('cx_Oracle.connect.cursor.execute')
    @patch('cx_Oracle.connect.cursor')
    @patch('cx_Oracle.connect')
    def test_query_not_limit(self, _conn, _cursor, _execute):
        _conn.return_value.cursor.return_value.fetchall.return_value = [(1,)]
        new_engine = OracleEngine(instance=self.ins)
        query_result = new_engine.query(db_name=0, sql='select 1', limit_num=0)
        self.assertIsInstance(query_result, ResultSet)
        self.assertListEqual(query_result.rows, [(1,)])

    @patch('sql.engines.oracle.OracleEngine.query',
           return_value=ResultSet(rows=[('AUD_SYS',), ('archery',), ('ANONYMOUS',)]))
    def test_get_all_databases(self, _query):
        new_engine = OracleEngine(instance=self.ins)
        dbs = new_engine.get_all_databases()
        self.assertListEqual(dbs.rows, ['archery'])

    @patch('sql.engines.oracle.OracleEngine.query',
           return_value=ResultSet(rows=[('ANONYMOUS',), ('archery',), ('SYSTEM',)]))
    def test_get_all_schemas(self, _query):
        new_engine = OracleEngine(instance=self.ins)
        schemas = new_engine._get_all_schemas()
        self.assertListEqual(schemas.rows, ['archery'])

    @patch('sql.engines.oracle.OracleEngine.query', return_value=ResultSet(rows=[('test',), ('test2',)]))
    def test_get_all_tables(self, _query):
        new_engine = OracleEngine(instance=self.ins)
        tables = new_engine.get_all_tables(db_name='archery')
        self.assertListEqual(tables.rows, ['test2'])

    @patch('sql.engines.oracle.OracleEngine.query',
           return_value=ResultSet(rows=[('id',), ('name',)]))
    def test_get_all_columns_by_tb(self, _query):
        new_engine = OracleEngine(instance=self.ins)
        columns = new_engine.get_all_columns_by_tb(db_name='archery', tb_name='test2')
        self.assertListEqual(columns.rows, ['id', 'name'])

    @patch('sql.engines.oracle.OracleEngine.query',
           return_value=ResultSet(rows=[('archery',), ('template1',), ('template0',)]))
    def test_describe_table(self, _query):
        new_engine = OracleEngine(instance=self.ins)
        describe = new_engine.describe_table(db_name='archery', tb_name='text')
        self.assertIsInstance(describe, ResultSet)

    def test_query_check_disable_sql(self):
        sql = "update xxx set a=1 "
        new_engine = OracleEngine(instance=self.ins)
        check_result = new_engine.query_check(db_name='archery', sql=sql)
        self.assertDictEqual(check_result,
                             {'msg': '仅支持^select语法!', 'bad_query': True, 'filtered_sql': sql.strip(),
                              'has_star': False})

    def test_query_check_star_sql(self):
        sql = "select * from xx "
        new_engine = OracleEngine(instance=self.ins)
        check_result = new_engine.query_check(db_name='archery', sql=sql)
        self.assertDictEqual(check_result,
                             {'msg': '禁止使用 * 关键词\n', 'bad_query': False, 'filtered_sql': sql.strip(), 'has_star': True})

    def test_filter_sql_with_delimiter(self):
        sql = "select * from xx;"
        new_engine = OracleEngine(instance=self.ins)
        check_result = new_engine.filter_sql(sql=sql, limit_num=100)
        self.assertEqual(check_result, "select * from xx WHERE ROWNUM <= 100")

    def test_filter_sql_without_delimiter(self):
        sql = "select * from xx"
        new_engine = OracleEngine(instance=self.ins)
        check_result = new_engine.filter_sql(sql=sql, limit_num=100)
        self.assertEqual(check_result, "select * from xx WHERE ROWNUM <= 100")

    def test_filter_sql_with_limit(self):
        sql = "select * from xx limit 10"
        new_engine = OracleEngine(instance=self.ins)
        check_result = new_engine.filter_sql(sql=sql, limit_num=1)
        self.assertEqual(check_result, "select * from xx limit 10 WHERE ROWNUM <= 1")

    def test_query_masking(self):
        query_result = ResultSet()
        new_engine = OracleEngine(instance=self.ins)
        masking_result = new_engine.query_masking(schema_name='', sql='', resultset=query_result)
        self.assertEqual(masking_result, query_result)

    def test_execute_check_select_sql(self):
        sql = 'select * from user'
        row = ReviewResult(id=1, errlevel=2,
                           stagestatus='驳回不支持语句',
                           errormessage='仅支持DML和DDL语句,查询语句请使用SQL查询功能!',
                           sql=sql)
        new_engine = OracleEngine(instance=self.ins)
        check_result = new_engine.execute_check(db_name='archery', sql=sql)
        self.assertIsInstance(check_result, ReviewSet)
        self.assertEqual(check_result.rows[0].__dict__, row.__dict__)

    def test_execute_check_critical_sql(self):
        self.sys_config.set('critical_ddl_regex', '^|update')
        self.sys_config.get_all_config()
        sql = 'update user set id=1'
        row = ReviewResult(id=1, errlevel=2,
                           stagestatus='驳回高危SQL',
                           errormessage='禁止提交匹配' + '^|update' + '条件的语句!',
                           sql=sql)
        new_engine = OracleEngine(instance=self.ins)
        check_result = new_engine.execute_check(db_name='archery', sql=sql)
        self.assertIsInstance(check_result, ReviewSet)
        self.assertEqual(check_result.rows[0].__dict__, row.__dict__)

    def test_execute_check_normal_sql(self):
        self.sys_config.purge()
        sql = 'update user set id=1'
        row = ReviewResult(id=1,
                           errlevel=0,
                           stagestatus='Audit completed',
                           errormessage='None',
                           sql=sql,
                           affected_rows=0,
                           execute_time=0, )
        new_engine = OracleEngine(instance=self.ins)
        check_result = new_engine.execute_check(db_name='archery', sql=sql)
        self.assertIsInstance(check_result, ReviewSet)
        self.assertEqual(check_result.rows[0].__dict__, row.__dict__)

    @patch('cx_Oracle.connect.cursor.execute')
    @patch('cx_Oracle.connect.cursor')
    @patch('cx_Oracle.connect')
    def test_execute_workflow_success(self, _conn, _cursor, _execute):
        sql = 'update user set id=1'
        row = ReviewResult(id=1,
                           errlevel=0,
                           stagestatus='Execute Successfully',
                           errormessage='None',
                           sql=sql,
                           affected_rows=0,
                           execute_time=0,
                           full_sql=sql)
        wf = SqlWorkflow.objects.create(
            workflow_name='some_name',
            group_id=1,
            group_name='g1',
            engineer_display='',
            audit_auth_groups='some_group',
            create_time=datetime.now() - timedelta(days=1),
            status='workflow_finish',
            is_backup=True,
            instance=self.ins,
            db_name='some_db',
            syntax_type=1
        )
        SqlWorkflowContent.objects.create(workflow=wf, sql_content=sql)
        new_engine = OracleEngine(instance=self.ins)
        execute_result = new_engine.execute_workflow(workflow=wf)
        self.assertIsInstance(execute_result, ReviewSet)
        self.assertEqual(execute_result.rows[0].__dict__.keys(), row.__dict__.keys())
Beispiel #13
0
class TestSQLReview(TestCase):
    """
    测试sql review内的方法
    """
    def setUp(self):
        self.superuser = User.objects.create(username='******',
                                             is_superuser=True)
        self.user = User.objects.create(username='******')
        # 使用 travis.ci 时实例和测试service保持一致
        self.master = Instance(
            instance_name='test_instance',
            type='master',
            db_type='mysql',
            host=settings.DATABASES['default']['HOST'],
            port=settings.DATABASES['default']['PORT'],
            user=settings.DATABASES['default']['USER'],
            password=settings.DATABASES['default']['PASSWORD'])
        self.master.save()
        self.sys_config = SysConfig()
        self.client = Client()
        self.group = ResourceGroup.objects.create(group_id=1,
                                                  group_name='group_name')
        self.wf1 = SqlWorkflow.objects.create(
            workflow_name='workflow_name',
            group_id=self.group.group_id,
            group_name=self.group.group_name,
            engineer=self.superuser.username,
            engineer_display=self.superuser.display,
            audit_auth_groups='audit_auth_groups',
            create_time=datetime.datetime.now(),
            status='workflow_review_pass',
            is_backup=True,
            instance=self.master,
            db_name='db_name',
            syntax_type=1,
        )
        self.wfc1 = SqlWorkflowContent.objects.create(workflow=self.wf1,
                                                      sql_content='some_sql',
                                                      execute_result='')

    def tearDown(self):
        self.wf1.delete()
        self.group.delete()
        self.superuser.delete()
        self.user.delete()
        self.master.delete()
        self.sys_config.replace(json.dumps({}))

    @patch('sql.engines.get_engine')
    def test_auto_review_hit_review_regex(
        self,
        _get_engine,
    ):
        """
        测试自动审批通过的判定条件,命中判断正则
        :return:
        """
        # 开启自动审批设置
        self.sys_config.set('auto_review', 'true')
        self.sys_config.set('auto_review_regex', '^drop')  # drop语句需要审批
        self.sys_config.set('auto_review_max_update_rows',
                            '50')  # update影响行数大于50需要审批
        self.sys_config.get_all_config()
        # 修改工单为drop
        self.wfc1.sql_content = "drop table users;"
        self.wfc1.save(update_fields=('sql_content', ))
        r = is_auto_review(self.wfc1.workflow_id)
        self.assertFalse(r)

    @patch('sql.engines.mysql.MysqlEngine.execute_check')
    @patch('sql.engines.get_engine')
    def test_auto_review_gt_max_update_rows(self, _get_engine, _execute_check):
        """
        测试自动审批通过的判定条件,影响行数大于auto_review_max_update_rows
        :return:
        """
        # 开启自动审批设置
        self.sys_config.set('auto_review', 'true')
        self.sys_config.set('auto_review_regex', '^drop')  # drop语句需要审批
        self.sys_config.set('auto_review_max_update_rows',
                            '2')  # update影响行数大于2需要审批
        self.sys_config.get_all_config()
        # 修改工单为update
        self.wfc1.sql_content = "update table users set email='';"
        self.wfc1.save(update_fields=('sql_content', ))
        # mock返回值,update影响行数=3
        _execute_check.return_value.to_dict.return_value = [{
            "id":
            1,
            "stage":
            "CHECKED",
            "errlevel":
            0,
            "stagestatus":
            "Audit completed",
            "errormessage":
            "None",
            "sql":
            "use archer_test",
            "affected_rows":
            0,
            "sequence":
            "'0_0_0'",
            "backup_dbname":
            "None",
            "execute_time":
            "0",
            "sqlsha1":
            "",
            "actual_affected_rows":
            'null'
        }, {
            "id":
            2,
            "stage":
            "CHECKED",
            "errlevel":
            0,
            "stagestatus":
            "Audit completed",
            "errormessage":
            "None",
            "sql":
            "update table users set email=''",
            "affected_rows":
            3,
            "sequence":
            "'0_0_1'",
            "backup_dbname":
            "mysql_3306_archer_test",
            "execute_time":
            "0",
            "sqlsha1":
            "",
            "actual_affected_rows":
            'null'
        }]
        r = is_auto_review(self.wfc1.workflow_id)
        self.assertFalse(r)

    @patch('sql.engines.mysql.MysqlEngine.execute_check')
    @patch('sql.engines.get_engine')
    def test_auto_review_true(self, _get_engine, _execute_check):
        """
        测试自动审批通过的判定条件,
        :return:
        """
        # 开启自动审批设置
        self.sys_config.set('auto_review', 'true')
        self.sys_config.set('auto_review_regex', '^drop')  # drop语句需要审批
        self.sys_config.set('auto_review_max_update_rows',
                            '2')  # update影响行数大于2需要审批
        self.sys_config.get_all_config()
        # 修改工单为update
        self.wfc1.sql_content = "update table users set email='';"
        self.wfc1.save(update_fields=('sql_content', ))
        # mock返回值,update影响行数=3
        _execute_check.return_value.to_dict.return_value = [{
            "id":
            1,
            "stage":
            "CHECKED",
            "errlevel":
            0,
            "stagestatus":
            "Audit completed",
            "errormessage":
            "None",
            "sql":
            "use archer_test",
            "affected_rows":
            0,
            "sequence":
            "'0_0_0'",
            "backup_dbname":
            "None",
            "execute_time":
            "0",
            "sqlsha1":
            "",
            "actual_affected_rows":
            'null'
        }, {
            "id":
            2,
            "stage":
            "CHECKED",
            "errlevel":
            0,
            "stagestatus":
            "Audit completed",
            "errormessage":
            "None",
            "sql":
            "update table users set email=''",
            "affected_rows":
            1,
            "sequence":
            "'0_0_1'",
            "backup_dbname":
            "mysql_3306_archer_test",
            "execute_time":
            "0",
            "sqlsha1":
            "",
            "actual_affected_rows":
            'null'
        }]
        r = is_auto_review(self.wfc1.workflow_id)
        self.assertTrue(r)

    def test_can_execute_for_resource_group(self, ):
        """
        测试是否能执行的判定条件,登录用户有资源组粒度执行权限,并且为组内用户
        :return:
        """
        # 修改工单为workflow_review_pass,登录用户有资源组粒度执行权限,并且为组内用户
        self.wf1.status = 'workflow_review_pass'
        self.wf1.save(update_fields=('status', ))
        sql_execute_for_resource_group = Permission.objects.get(
            codename='sql_execute_for_resource_group')
        self.user.user_permissions.add(sql_execute_for_resource_group)
        ResourceGroupRelations.objects.create(object_type=0,
                                              object_id=self.user.id,
                                              group_id=self.group.group_id)
        r = can_execute(user=self.user, workflow_id=self.wfc1.workflow_id)
        self.assertTrue(r)

    def test_can_execute_true(self, ):
        """
        测试是否能执行的判定条件,当前登录用户为提交人,并且有执行权限,工单状态为审核通过
        :return:
        """
        # 修改工单为workflow_review_pass,当前登录用户为提交人,并且有执行权限
        self.wf1.status = 'workflow_review_pass'
        self.wf1.engineer = self.user.username
        self.wf1.save(update_fields=('status', 'engineer'))
        sql_execute = Permission.objects.get(codename='sql_execute')
        self.user.user_permissions.add(sql_execute)
        r = can_execute(user=self.user, workflow_id=self.wfc1.workflow_id)
        self.assertTrue(r)

    def test_can_execute_workflow_timing_task(self, ):
        """
        测试是否能执行的判定条件,当前登录用户为提交人,并且有执行权限,工单状态为定时执行
        :return:
        """
        # 修改工单为workflow_review_pass,当前登录用户为提交人,并且有执行权限
        self.wf1.status = 'workflow_timingtask'
        self.wf1.engineer = self.user.username
        self.wf1.save(update_fields=('status', 'engineer'))
        sql_execute = Permission.objects.get(codename='sql_execute')
        self.user.user_permissions.add(sql_execute)
        r = can_execute(user=self.user, workflow_id=self.wfc1.workflow_id)
        self.assertTrue(r)

    def test_can_execute_false_no_permission(self, ):
        """
        当前登录用户为提交人,但是没有执行权限
        :return:
        """
        # 修改工单为workflow_review_pass,当前登录用户为提交人,并且有执行权限
        self.wf1.status = 'workflow_timingtask'
        self.wf1.engineer = self.user.username
        self.wf1.save(update_fields=('status', 'engineer'))
        r = can_execute(user=self.user, workflow_id=self.wfc1.workflow_id)
        self.assertFalse(r)

    def test_can_execute_false_not_in_group(self, ):
        """
        当前登录用户为提交人,有资源组粒度执行权限,但是不是组内用户
        :return:
        """
        # 修改工单为workflow_review_pass,有资源组粒度执行权限,但是不是组内用户
        self.wf1.status = 'workflow_review_pass'
        self.wf1.save(update_fields=('status', ))
        sql_execute_for_resource_group = Permission.objects.get(
            codename='sql_execute_for_resource_group')
        self.user.user_permissions.add(sql_execute_for_resource_group)
        r = can_execute(user=self.user, workflow_id=self.wfc1.workflow_id)
        self.assertFalse(r)

    def test_can_execute_false_wrong_status(self, ):
        """
        当前登录用户为提交人,前登录用户为提交人,并且有执行权限,但是工单状态为待审核
        :return:
        """
        # 修改工单为workflow_manreviewing,当前登录用户为提交人,并且有执行权限, 但是工单状态为待审核
        self.wf1.status = 'workflow_manreviewing'
        self.wf1.engineer = self.user.username
        self.wf1.save(update_fields=('status', 'engineer'))
        sql_execute = Permission.objects.get(codename='sql_execute')
        self.user.user_permissions.add(sql_execute)
        r = can_execute(user=self.user, workflow_id=self.wfc1.workflow_id)
        self.assertFalse(r)

    def test_can_timingtask_true(self, ):
        """
        测试是否能定时执行的判定条件,当前登录用户为提交人,并且有执行权限,工单状态为审核通过
        :return:
        """
        # 修改工单为workflow_review_pass,当前登录用户为提交人,并且有执行权限
        self.wf1.status = 'workflow_review_pass'
        self.wf1.engineer = self.user.username
        self.wf1.save(update_fields=('status', 'engineer'))
        sql_execute = Permission.objects.get(codename='sql_execute')
        self.user.user_permissions.add(sql_execute)
        r = can_timingtask(user=self.user, workflow_id=self.wfc1.workflow_id)
        self.assertTrue(r)

    def test_can_timingtask_false(self, ):
        """
        测试是否能定时执行的判定条件,当前登录有执行权限,工单状态为审核通过,但用户不是提交人
        :return:
        """
        # 修改工单为workflow_review_pass,当前登录用户为提交人,并且有执行权限
        self.wf1.status = 'workflow_review_pass'
        self.wf1.engineer = self.superuser.username
        self.wf1.save(update_fields=('status', 'engineer'))
        sql_execute = Permission.objects.get(codename='sql_execute')
        self.user.user_permissions.add(sql_execute)
        r = can_timingtask(user=self.user, workflow_id=self.wfc1.workflow_id)
        self.assertFalse(r)

    @patch('sql.utils.workflow_audit.Audit.can_review')
    def test_can_cancel_true_for_apply_user(self, _can_review):
        """
        测试是否能取消,审核中的工单,提交人可终止
        :return:
        """
        # 修改工单为workflow_review_pass,当前登录用户为提交人
        self.wf1.status = 'workflow_manreviewing'
        self.wf1.engineer = self.user.username
        self.wf1.save(update_fields=('status', 'engineer'))
        _can_review.return_value = False
        r = can_cancel(user=self.user, workflow_id=self.wfc1.workflow_id)
        self.assertTrue(r)

    @patch('sql.utils.workflow_audit.Audit.can_review')
    def test_can_cancel_true_for_audit_user(self, _can_review):
        """
        测试是否能取消,审核中的工单,审核人可终止
        :return:
        """
        # 修改工单为workflow_review_pass,当前登录用户为提交人
        self.wf1.status = 'workflow_manreviewing'
        self.wf1.engineer = self.superuser.username
        self.wf1.save(update_fields=('status', 'engineer'))
        _can_review.return_value = True
        r = can_cancel(user=self.user, workflow_id=self.wfc1.workflow_id)
        self.assertTrue(r)

    @patch('sql.utils.sql_review.can_execute')
    def test_can_cancel_true_for_execute_user(self, _can_execute):
        """
        测试是否能取消,审核通过但未执行的工单,有执行权限的用户终止
        :return:
        """
        # 修改工单为workflow_review_pass,当前登录用户为提交人
        self.wf1.status = 'workflow_review_pass'
        self.wf1.engineer = self.user.username
        self.wf1.save(update_fields=('status', 'engineer'))
        _can_execute.return_value = True
        r = can_cancel(user=self.user, workflow_id=self.wfc1.workflow_id)
        self.assertTrue(r)

    @patch('sql.utils.sql_review.can_execute')
    def test_can_cancel_false(self, _can_execute):
        """
        测试是否能取消,审核通过但未执行的工单,无执行权限的用户无法终止
        :return:
        """
        # 修改工单为workflow_review_pass,当前登录用户为提交人
        self.wf1.status = 'workflow_review_pass'
        self.wf1.engineer = self.user.username
        self.wf1.save(update_fields=('status', 'engineer'))
        _can_execute.return_value = False
        r = can_cancel(user=self.user, workflow_id=self.wfc1.workflow_id)
        self.assertFalse(r)
Beispiel #14
0
 def test_set_other_data(self):
     archer_config = SysConfig()
     archer_config.set('other_config', 'testvalue3')
     self.assertEqual(archer_config.sys_config['other_config'],
                      'testvalue3')
Beispiel #15
0
 def test_set_bool_transform(self):
     archer_config = SysConfig()
     archer_config.set('boolconfig3', False)
     self.assertEqual(archer_config.sys_config['boolconfig3'], False)
Beispiel #16
0
class TestBinLog(TestCase):
    """
    测试Binlog相关
    """
    def setUp(self):
        self.superuser = User(username='******', is_superuser=True)
        self.superuser.save()
        # 使用 travis.ci 时实例和测试service保持一致
        self.master = Instance(
            instance_name='test_instance',
            type='master',
            db_type='mysql',
            host=settings.DATABASES['default']['HOST'],
            port=settings.DATABASES['default']['PORT'],
            user=settings.DATABASES['default']['USER'],
            password=settings.DATABASES['default']['PASSWORD'])
        self.master.save()
        self.sys_config = SysConfig()
        self.client = Client()
        self.client.force_login(self.superuser)

    def tearDown(self):
        self.superuser.delete()
        self.master.delete()
        self.sys_config.replace(json.dumps({}))

    def test_binlog_list_instance_not_exist(self):
        """
        测试获取binlog列表,实例不存在
        :return:
        """
        data = {"instance_name": 'some_instance'}
        r = self.client.post(path='/binlog/list/', data=data)
        self.assertEqual(json.loads(r.content), {
            'status': 1,
            'msg': '实例不存在',
            'data': []
        })

    def test_binlog_list_instance(self):
        """
        测试获取binlog列表,实例存在
        :return:
        """
        data = {"instance_name": 'test_instance'}
        r = self.client.post(path='/binlog/list/', data=data)
        self.assertEqual(json.loads(r.content).get('status'), 0)

    def test_binlog2sql_path_not_exist(self):
        """
        测试获取解析binlog,path未设置
        :return:
        """
        data = {
            "instance_name": "test_instance",
            "save_sql": "false",
            "no_pk": "false",
            "flashback": "false",
            "back_interval": "",
            "num": "",
            "start_file": "mysql-bin.000045",
            "start_pos": "",
            "end_file": "",
            "end_pos": "",
            "stop_time": "",
            "start_time": "",
            "only_schemas": "",
            "only_dml": "true",
            "sql_type": ""
        }
        r = self.client.post(path='/binlog/binlog2sql/', data=data)
        self.assertEqual(json.loads(r.content), {
            'status': 1,
            'msg': '可执行文件路径不能为空!',
            'data': {}
        })

    @patch('sql.plugins.plugin.subprocess')
    def test_binlog2sql(self, _subprocess):
        """
        测试获取解析binlog,path设置
        :param _subprocess:
        :return:
        """
        self.sys_config.set('binlog2sql', '/opt/binlog2sql')
        self.sys_config.get_all_config()
        data = {
            "instance_name": "test_instance",
            "save_sql": "1",
            "no_pk": "false",
            "flashback": "false",
            "back_interval": "",
            "num": "1",
            "start_file": "mysql-bin.000045",
            "start_pos": "",
            "end_file": "",
            "end_pos": "",
            "stop_time": "",
            "start_time": "",
            "only_schemas": "",
            "only_dml": "true",
            "sql_type": ""
        }
        r = self.client.post(path='/binlog/binlog2sql/', data=data)
        self.assertEqual(json.loads(r.content), {
            "status": 0,
            "msg": "ok",
            "data": [{
                "sql": {},
                "binlog_info": {}
            }]
        })

    @patch('builtins.iter')
    @patch('sql.plugins.plugin.subprocess')
    def test_binlog2sql_file(self, _subprocess, _iter):
        """
        测试保存文件
        :param _subprocess:
        :return:
        """
        args = {
            "instance_name": "test_instance",
            "save_sql": "1",
            "no_pk": "false",
            "flashback": "false",
            "back_interval": "",
            "num": "1",
            "start_file": "",
            "start_pos": "",
            "end_file": "",
            "end_pos": "",
            "stop_time": "",
            "start_time": "",
            "only_schemas": "",
            "only_dml": "true",
            "sql_type": "",
            "instance": self.master
        }
        _subprocess.Popen.return_value.stdout.return_value.readline.return_value = 'sql'
        _iter.return_value = ''
        r = binlog2sql_file(args=args, user=self.superuser)
        self.assertEqual(self.superuser, r[0])

    def test_del_binlog_instance_not_exist(self):
        """
        测试删除binlog,实例不存在
        :return:
        """
        data = {
            "instance_id": 0,
            "binlog": "mysql-bin.000001",
        }
        r = self.client.post(path='/binlog/del_log/', data=data)
        self.assertEqual(json.loads(r.content), {
            'status': 1,
            'msg': '实例不存在',
            'data': []
        })

    def test_del_binlog_binlog_not_exist(self):
        """
        测试删除binlog,实例存在,binlog 不存在
        :return:
        """
        data = {"instance_id": self.master.id, "binlog": ''}
        r = self.client.post(path='/binlog/del_log/', data=data)
        self.assertEqual(json.loads(r.content), {
            'status': 1,
            'msg': 'Error:未选择binlog!',
            'data': ''
        })

    @patch('sql.engines.mysql.MysqlEngine.query')
    @patch('sql.engines.get_engine')
    def test_del_binlog(self, _get_engine, _query):
        """
        测试删除binlog
        :return:
        """
        data = {"instance_id": self.master.id, "binlog": "mysql-bin.000001"}
        _query.return_value = ResultSet(full_sql='select 1')
        r = self.client.post(path='/binlog/del_log/', data=data)
        self.assertEqual(json.loads(r.content), {
            'status': 0,
            'msg': '清理成功',
            'data': ''
        })

    @patch('sql.engines.mysql.MysqlEngine.query')
    @patch('sql.engines.get_engine')
    def test_del_binlog_wrong(self, _get_engine, _query):
        """
        测试删除binlog
        :return:
        """
        data = {"instance_id": self.master.id, "binlog": "mysql-bin.000001"}
        _query.return_value = ResultSet(full_sql='select 1')
        _query.return_value.error = '清理失败'
        r = self.client.post(path='/binlog/del_log/', data=data)
        self.assertEqual(json.loads(r.content), {
            'status': 2,
            'msg': '清理失败,Error:清理失败',
            'data': ''
        })
Beispiel #17
0
class TestPlugin(TestCase):
    """
    测试Plugin调用
    """
    def setUp(self):
        self.superuser = User(username='******', is_superuser=True)
        self.superuser.save()
        self.sys_config = SysConfig()
        self.client = Client()
        self.client.force_login(self.superuser)

    def tearDown(self):
        self.superuser.delete()
        self.sys_config.replace(json.dumps({}))

    def test_check_args_path(self):
        """
        测试路径
        :return:
        """
        args = {
            "online-dsn": '',
            "test-dsn": '',
            "allow-online-as-test": "false",
            "report-type": "markdown",
            "query": "select 1;"
        }
        self.sys_config.set('soar', '')
        self.sys_config.get_all_config()
        soar = Soar()
        args_check_result = soar.check_args(args)
        self.assertDictEqual(args_check_result, {
            'status': 1,
            'msg': '可执行文件路径不能为空!',
            'data': {}
        })
        # 路径不为空
        self.sys_config.set('soar', '/opt/archery/src/plugins/soar')
        self.sys_config.get_all_config()
        soar = Soar()
        args_check_result = soar.check_args(args)
        self.assertDictEqual(args_check_result, {
            'status': 0,
            'msg': 'ok',
            'data': {}
        })

    def test_check_args_disable(self):
        """
        测试禁用参数
        :return:
        """
        args = {
            "online-dsn": '',
            "test-dsn": '',
            "allow-online-as-test": "false",
            "report-type": "markdown",
            "query": "select 1;"
        }
        self.sys_config.set('soar', '/opt/archery/src/plugins/soar')
        self.sys_config.get_all_config()
        soar = Soar()
        soar.disable_args = ['allow-online-as-test']
        args_check_result = soar.check_args(args)
        self.assertDictEqual(args_check_result, {
            'status': 1,
            'msg': 'allow-online-as-test参数已被禁用',
            'data': {}
        })

    def test_check_args_required(self):
        """
        测试必选参数
        :return:
        """
        args = {
            "online-dsn": '',
            "test-dsn": '',
            "allow-online-as-test": "false",
            "report-type": "markdown",
        }
        self.sys_config.set('soar', '/opt/archery/src/plugins/soar')
        self.sys_config.get_all_config()
        soar = Soar()
        soar.required_args = ['query']
        args_check_result = soar.check_args(args)
        self.assertDictEqual(args_check_result, {
            'status': 1,
            'msg': '必须指定query参数',
            'data': {}
        })
        args['query'] = ""
        args_check_result = soar.check_args(args)
        self.assertDictEqual(args_check_result, {
            'status': 1,
            'msg': 'query参数值不能为空',
            'data': {}
        })

    def test_soar_generate_args2cmd(self):
        args = {
            "online-dsn": '',
            "test-dsn": '',
            "allow-online-as-test": "false",
            "report-type": "markdown",
            "query": "select 1;"
        }
        self.sys_config.set('soar', '/opt/archery/src/plugins/soar')
        self.sys_config.get_all_config()
        soar = Soar()
        cmd_args = soar.generate_args2cmd(args, False)
        self.assertIsInstance(cmd_args, list)
        cmd_args = soar.generate_args2cmd(args, True)
        self.assertIsInstance(cmd_args, str)

    def test_sql_advisor_generate_args2cmd(self):
        args = {
            "h": 'mysql',
            "P": 3306,
            "u": 'root',
            "p": '',
            "d": 'archery',
            "v": 1,
            "q": 'select 1;'
        }
        self.sys_config.set('sqladvisor',
                            '/opt/archery/src/plugins/SQLAdvisor')
        self.sys_config.get_all_config()
        sql_advisor = SQLAdvisor()
        cmd_args = sql_advisor.generate_args2cmd(args, False)
        self.assertIsInstance(cmd_args, list)
        cmd_args = sql_advisor.generate_args2cmd(args, True)
        self.assertIsInstance(cmd_args, str)

    def test_execute_cmd(self):
        args = {
            "online-dsn": '',
            "test-dsn": '',
            "allow-online-as-test": "false",
            "report-type": "markdown",
            "query": "select 1;"
        }
        self.sys_config.set('soar', '/opt/archery/src/plugins/soar')
        self.sys_config.get_all_config()
        soar = Soar()
        cmd_args = soar.generate_args2cmd(args, True)
        result = soar.execute_cmd(cmd_args, True)
        self.assertIn('/opt/archery/src/plugins/soar', result)
        # 异常
        with self.assertRaises(RuntimeError):
            soar.execute_cmd(cmd_args, False)
Beispiel #18
0
class TestOptimize(TestCase):
    """
    测试SQL优化
    """

    def setUp(self):
        self.superuser = User(username='******', is_superuser=True)
        self.superuser.save()
        # 使用 travis.ci 时实例和测试service保持一致
        self.master = Instance(instance_name='test_instance', type='master', db_type='mysql',
                               host=settings.DATABASES['default']['HOST'],
                               port=settings.DATABASES['default']['PORT'],
                               user=settings.DATABASES['default']['USER'],
                               password=settings.DATABASES['default']['PASSWORD'])
        self.master.save()
        self.sys_config = SysConfig()
        self.client = Client()
        self.client.force_login(self.superuser)

    def tearDown(self):
        self.superuser.delete()
        self.master.delete()
        self.sys_config.replace(json.dumps({}))

    def test_sqladvisor(self):
        """
        测试SQLAdvisor报告
        :return:
        """
        r = self.client.post(path='/slowquery/optimize_sqladvisor/')
        self.assertEqual(json.loads(r.content), {'status': 1, 'msg': '页面提交参数可能为空', 'data': []})
        r = self.client.post(path='/slowquery/optimize_sqladvisor/',
                             data={"sql_content": "select 1;", "instance_name": "test_instance"})
        self.assertEqual(json.loads(r.content), {'status': 1, 'msg': '请配置SQLAdvisor路径!', 'data': []})
        self.sys_config.set('sqladvisor', '/opt/archery/src/plugins/sqladvisor')
        self.sys_config.get_all_config()
        r = self.client.post(path='/slowquery/optimize_sqladvisor/',
                             data={"sql_content": "select 1;", "instance_name": "test_instance"})
        self.assertEqual(json.loads(r.content)['status'], 0)

    def test_soar(self):
        """
        测试SOAR报告
        :return:
        """
        r = self.client.post(path='/slowquery/optimize_soar/')
        self.assertEqual(json.loads(r.content), {'status': 1, 'msg': '页面提交参数可能为空', 'data': []})
        r = self.client.post(path='/slowquery/optimize_soar/',
                             data={"sql": "select 1;", "instance_name": "test_instance", "db_name": "mysql"})
        self.assertEqual(json.loads(r.content), {'status': 1, 'msg': '请配置soar_path和test_dsn!', 'data': []})
        self.sys_config.set('soar', '/opt/archery/src/plugins/soar')
        self.sys_config.set('soar_test_dsn', 'root:@127.0.0.1:3306/information_schema')
        self.sys_config.get_all_config()
        r = self.client.post(path='/slowquery/optimize_soar/',
                             data={"sql": "select 1;", "instance_name": "test_instance", "db_name": "mysql"})
        self.assertEqual(json.loads(r.content)['status'], 0)

    def test_tuning(self):
        """
        测试SQLTuning报告
        :return:
        """
        data = {"sql_content": "select * from test_archery.sql_users;",
                "instance_name": "test_instance",
                "db_name": settings.DATABASES['default']['TEST']['NAME']
                }
        r = self.client.post(path='/slowquery/optimize_sqltuning/')
        self.assertEqual(json.loads(r.content), {'status': 1, 'msg': '实例不存在', 'data': []})

        # 获取sys_parm
        data['option[]'] = 'sys_parm'
        r = self.client.post(path='/slowquery/optimize_sqltuning/', data=data)
        self.assertListEqual(list(json.loads(r.content)['data'].keys()),
                             ['basic_information', 'sys_parameter', 'optimizer_switch', 'sqltext'])

        # 获取sql_plan
        data['option[]'] = 'sql_plan'
        r = self.client.post(path='/slowquery/optimize_sqltuning/', data=data)
        self.assertListEqual(list(json.loads(r.content)['data'].keys()),
                             ['optimizer_rewrite_sql', 'plan', 'sqltext'])

        # 获取obj_stat
        data['option[]'] = 'obj_stat'
        r = self.client.post(path='/slowquery/optimize_sqltuning/', data=data)
        self.assertListEqual(list(json.loads(r.content)['data'].keys()),
                             ['object_statistics', 'sqltext'])

        # 获取sql_profile
        data['option[]'] = 'sql_profile'
        r = self.client.post(path='/slowquery/optimize_sqltuning/', data=data)
        self.assertListEqual(list(json.loads(r.content)['data'].keys()), ['session_status', 'sqltext'])
Beispiel #19
0
class TestPlugin(TestCase):
    """
    测试Plugin调用
    """
    def setUp(self):
        self.superuser = User(username='******', is_superuser=True)
        self.superuser.save()
        self.sys_config = SysConfig()
        self.client = Client()
        self.client.force_login(self.superuser)

    def tearDown(self):
        self.superuser.delete()
        self.sys_config.replace(json.dumps({}))

    def test_check_args_path(self):
        """
        测试路径
        :return:
        """
        args = {
            "online-dsn": '',
            "test-dsn": '',
            "allow-online-as-test": "false",
            "report-type": "markdown",
            "query": "select 1;"
        }
        self.sys_config.set('soar', '')
        self.sys_config.get_all_config()
        soar = Soar()
        args_check_result = soar.check_args(args)
        self.assertDictEqual(args_check_result, {
            'status': 1,
            'msg': '可执行文件路径不能为空!',
            'data': {}
        })
        # 路径不为空
        self.sys_config.set('soar', '/opt/archery/src/plugins/soar')
        self.sys_config.get_all_config()
        soar = Soar()
        args_check_result = soar.check_args(args)
        self.assertDictEqual(args_check_result, {
            'status': 0,
            'msg': 'ok',
            'data': {}
        })

    def test_check_args_disable(self):
        """
        测试禁用参数
        :return:
        """
        args = {
            "online-dsn": '',
            "test-dsn": '',
            "allow-online-as-test": "false",
            "report-type": "markdown",
            "query": "select 1;"
        }
        self.sys_config.set('soar', '/opt/archery/src/plugins/soar')
        self.sys_config.get_all_config()
        soar = Soar()
        soar.disable_args = ['allow-online-as-test']
        args_check_result = soar.check_args(args)
        self.assertDictEqual(args_check_result, {
            'status': 1,
            'msg': 'allow-online-as-test参数已被禁用',
            'data': {}
        })

    def test_check_args_required(self):
        """
        测试必选参数
        :return:
        """
        args = {
            "online-dsn": '',
            "test-dsn": '',
            "allow-online-as-test": "false",
            "report-type": "markdown",
        }
        self.sys_config.set('soar', '/opt/archery/src/plugins/soar')
        self.sys_config.get_all_config()
        soar = Soar()
        soar.required_args = ['query']
        args_check_result = soar.check_args(args)
        self.assertDictEqual(args_check_result, {
            'status': 1,
            'msg': '必须指定query参数',
            'data': {}
        })
        args['query'] = ""
        args_check_result = soar.check_args(args)
        self.assertDictEqual(args_check_result, {
            'status': 1,
            'msg': 'query参数值不能为空',
            'data': {}
        })

    def test_soar_generate_args2cmd(self):
        args = {
            "online-dsn": '',
            "test-dsn": '',
            "allow-online-as-test": "false",
            "report-type": "markdown",
            "query": "select 1;"
        }
        self.sys_config.set('soar', '/opt/archery/src/plugins/soar')
        self.sys_config.get_all_config()
        soar = Soar()
        cmd_args = soar.generate_args2cmd(args, False)
        self.assertIsInstance(cmd_args, list)
        cmd_args = soar.generate_args2cmd(args, True)
        self.assertIsInstance(cmd_args, str)

    def test_sql_advisor_generate_args2cmd(self):
        args = {
            "h": 'mysql',
            "P": 3306,
            "u": 'root',
            "p": '',
            "d": 'archery',
            "v": 1,
            "q": 'select 1;'
        }
        self.sys_config.set('sqladvisor',
                            '/opt/archery/src/plugins/SQLAdvisor')
        self.sys_config.get_all_config()
        sql_advisor = SQLAdvisor()
        cmd_args = sql_advisor.generate_args2cmd(args, False)
        self.assertIsInstance(cmd_args, list)
        cmd_args = sql_advisor.generate_args2cmd(args, True)
        self.assertIsInstance(cmd_args, str)

    def test_schema_sync_generate_args2cmd(self):
        args = {
            "sync-auto-inc":
            True,
            "sync-comments":
            True,
            "tag":
            'tag_v',
            "output-directory":
            '',
            "source":
            r"mysql://{user}:{pwd}@{host}:{port}/{database}".format(
                user='******',
                pwd='123456',
                host='127.0.0.1',
                port=3306,
                database='*'),
            "target":
            r"mysql://{user}:{pwd}@{host}:{port}/{database}".format(
                user='******',
                pwd='123456',
                host='127.0.0.1',
                port=3306,
                database='*')
        }
        self.sys_config.set('schemasync',
                            '/opt/venv4schemasync/bin/schemasync')
        self.sys_config.get_all_config()
        schema_sync = SchemaSync()
        cmd_args = schema_sync.generate_args2cmd(args, False)
        self.assertIsInstance(cmd_args, list)
        cmd_args = schema_sync.generate_args2cmd(args, True)
        self.assertIsInstance(cmd_args, str)

    def test_execute_cmd(self):
        args = {
            "online-dsn": '',
            "test-dsn": '',
            "allow-online-as-test": "false",
            "report-type": "markdown",
            "query": "select 1;"
        }
        self.sys_config.set('soar', '/opt/archery/src/plugins/soar')
        self.sys_config.get_all_config()
        soar = Soar()
        cmd_args = soar.generate_args2cmd(args, True)
        result = soar.execute_cmd(cmd_args, True)
        self.assertIn('/opt/archery/src/plugins/soar', result)
        # 异常
        with self.assertRaises(RuntimeError):
            soar.execute_cmd(cmd_args, False)
Beispiel #20
0
class TestMysql(TestCase):
    def setUp(self):
        self.ins1 = Instance(instance_name='some_ins',
                             type='slave',
                             db_type='mysql',
                             host='some_host',
                             port=1366,
                             user='******',
                             password='******')
        self.ins1.save()
        self.sys_config = SysConfig()
        self.wf = SqlWorkflow.objects.create(workflow_name='some_name',
                                             group_id=1,
                                             group_name='g1',
                                             engineer_display='',
                                             audit_auth_groups='some_group',
                                             create_time=datetime.now() -
                                             timedelta(days=1),
                                             status='workflow_finish',
                                             is_backup='是',
                                             instance=self.ins1,
                                             db_name='some_db',
                                             syntax_type=1)
        SqlWorkflowContent.objects.create(workflow=self.wf)

    def tearDown(self):
        self.ins1.delete()
        self.sys_config.replace(json.dumps({}))
        SqlWorkflow.objects.all().delete()
        SqlWorkflowContent.objects.all().delete()

    @patch('MySQLdb.connect')
    def testGetConnection(self, connect):
        new_engine = MysqlEngine(instance=self.ins1)
        new_engine.get_connection()
        connect.assert_called_once()

    @patch('MySQLdb.connect')
    def testQuery(self, connect):
        cur = Mock()
        connect.return_value.cursor = cur
        cur.return_value.execute = Mock()
        cur.return_value.fetchmany.return_value = (('v1', 'v2'), )
        cur.return_value.description = (('k1', 'some_other_des'),
                                        ('k2', 'some_other_des'))
        new_engine = MysqlEngine(instance=self.ins1)
        query_result = new_engine.query(sql='some_str', limit_num=100)
        cur.return_value.execute.assert_called()
        cur.return_value.fetchmany.assert_called_once_with(size=100)
        connect.return_value.close.assert_called_once()
        self.assertIsInstance(query_result, ResultSet)

    @patch.object(MysqlEngine, 'query')
    def testAllDb(self, mock_query):
        db_result = ResultSet()
        db_result.rows = [('db_1', ), ('db_2', )]
        mock_query.return_value = db_result
        new_engine = MysqlEngine(instance=self.ins1)
        dbs = new_engine.get_all_databases()
        self.assertEqual(dbs, ['db_1', 'db_2'])

    @patch.object(MysqlEngine, 'query')
    def testAllTables(self, mock_query):
        table_result = ResultSet()
        table_result.rows = [('tb_1', 'some_des'), ('tb_2', 'some_des')]
        mock_query.return_value = table_result
        new_engine = MysqlEngine(instance=self.ins1)
        tables = new_engine.get_all_tables('some_db')
        mock_query.assert_called_once_with(db_name='some_db', sql=ANY)
        self.assertEqual(tables, ['tb_1', 'tb_2'])

    @patch.object(MysqlEngine, 'query')
    def testAllColumns(self, mock_query):
        db_result = ResultSet()
        db_result.rows = [('col_1', 'type'), ('col_2', 'type2')]
        mock_query.return_value = db_result
        new_engine = MysqlEngine(instance=self.ins1)
        dbs = new_engine.get_all_columns_by_tb('some_db', 'some_tb')
        self.assertEqual(dbs, ['col_1', 'col_2'])

    @patch.object(MysqlEngine, 'query')
    def testDescribe(self, mock_query):
        new_engine = MysqlEngine(instance=self.ins1)
        new_engine.describe_table('some_db', 'some_db')
        mock_query.assert_called_once()

    def testQueryCheck(self):
        new_engine = MysqlEngine(instance=self.ins1)
        sql_without_limit = '-- 测试\n select user from usertable'
        check_result = new_engine.query_check(db_name='some_db',
                                              sql=sql_without_limit)
        self.assertEqual(check_result['filtered_sql'],
                         'select user from usertable')

    def test_query_check_wrong_sql(self):
        new_engine = MysqlEngine(instance=self.ins1)
        wrong_sql = '-- 测试'
        check_result = new_engine.query_check(db_name='some_db', sql=wrong_sql)
        self.assertDictEqual(
            check_result, {
                'msg': '不支持的查询语法类型!',
                'bad_query': True,
                'filtered_sql': '-- 测试',
                'has_star': True
            })

    def test_query_check_update_sql(self):
        new_engine = MysqlEngine(instance=self.ins1)
        update_sql = 'update user set id=0'
        check_result = new_engine.query_check(db_name='some_db',
                                              sql=update_sql)
        self.assertDictEqual(
            check_result, {
                'msg': '不支持的查询语法类型!',
                'bad_query': True,
                'filtered_sql': 'update user set id=0',
                'has_star': False
            })

    def test_filter_sql_with_delimiter(self):
        new_engine = MysqlEngine(instance=self.ins1)
        sql_without_limit = 'select user from usertable;'
        check_result = new_engine.filter_sql(sql=sql_without_limit,
                                             limit_num=100)
        self.assertEqual(check_result, 'select user from usertable limit 100;')

    def test_filter_sql_without_delimiter(self):
        new_engine = MysqlEngine(instance=self.ins1)
        sql_without_limit = 'select user from usertable'
        check_result = new_engine.filter_sql(sql=sql_without_limit,
                                             limit_num=100)
        self.assertEqual(check_result, 'select user from usertable limit 100;')

    def test_filter_sql_with_limit(self):
        new_engine = MysqlEngine(instance=self.ins1)
        sql_without_limit = 'select user from usertable limit 10'
        check_result = new_engine.filter_sql(sql=sql_without_limit,
                                             limit_num=1)
        self.assertEqual(check_result, 'select user from usertable limit 10;')

    @patch('sql.engines.mysql.data_masking', return_value=ResultSet())
    def test_query_masking(self, _data_masking):
        query_result = ResultSet()
        new_engine = MysqlEngine(instance=self.ins1)
        masking_result = new_engine.query_masking(db_name='archery',
                                                  sql='select 1',
                                                  resultset=query_result)
        self.assertIsInstance(masking_result, ResultSet)

    @patch('sql.engines.mysql.data_masking', return_value=ResultSet())
    def test_query_masking_not_select(self, _data_masking):
        query_result = ResultSet()
        new_engine = MysqlEngine(instance=self.ins1)
        masking_result = new_engine.query_masking(db_name='archery',
                                                  sql='explain select 1',
                                                  resultset=query_result)
        self.assertEqual(masking_result, query_result)

    def test_execute_check_select_sql(self):
        sql = 'select * from user'
        row = ReviewResult(id=1,
                           errlevel=2,
                           stagestatus='驳回高危SQL',
                           errormessage='仅支持DML和DDL语句,查询语句请使用SQL查询功能!',
                           sql=sql)
        new_engine = MysqlEngine(instance=self.ins1)
        check_result = new_engine.execute_check(db_name='archery', sql=sql)
        self.assertIsInstance(check_result, ReviewSet)
        self.assertEqual(check_result.rows[0].__dict__, row.__dict__)

    def test_execute_check_critical_sql(self):
        self.sys_config.set('critical_ddl_regex', '^|update')
        self.sys_config.get_all_config()
        sql = 'update user set id=1'
        row = ReviewResult(id=1,
                           errlevel=2,
                           stagestatus='驳回高危SQL',
                           errormessage='禁止提交匹配' + '^|update' + '条件的语句!',
                           sql=sql)
        new_engine = MysqlEngine(instance=self.ins1)
        check_result = new_engine.execute_check(db_name='archery', sql=sql)
        self.assertIsInstance(check_result, ReviewSet)
        self.assertEqual(check_result.rows[0].__dict__, row.__dict__)

    @patch('sql.engines.mysql.InceptionEngine')
    def test_execute_check_normal_sql(self, _inception_engine):
        sql = 'update user set id=1'
        row = ReviewResult(
            id=1,
            errlevel=0,
            stagestatus='Audit completed',
            errormessage='None',
            sql=sql,
            affected_rows=0,
            execute_time=0,
        )
        _inception_engine.return_value.execute_check.return_value = ReviewSet(
            full_sql=sql, rows=[row])
        new_engine = MysqlEngine(instance=self.ins1)
        check_result = new_engine.execute_check(db_name='archery', sql=sql)
        self.assertIsInstance(check_result, ReviewSet)
        self.assertEqual(check_result.rows[0].__dict__, row.__dict__)

    @patch('sql.engines.mysql.InceptionEngine')
    def test_execute_check_normal_sql_with_Exception(self, _inception_engine):
        sql = 'update user set id=1'
        _inception_engine.return_value.execute_check.side_effect = RuntimeError(
        )
        new_engine = MysqlEngine(instance=self.ins1)
        with self.assertRaises(RuntimeError):
            new_engine.execute_check(db_name=0, sql=sql)

    @patch('sql.engines.mysql.InceptionEngine')
    def test_execute_workflow(self, _inception_engine):
        sql = 'update user set id=1'
        _inception_engine.return_value.execute.return_value = ReviewSet(
            full_sql=sql)
        new_engine = MysqlEngine(instance=self.ins1)
        execute_result = new_engine.execute_workflow(self.wf)
        self.assertIsInstance(execute_result, ReviewSet)

    @patch('MySQLdb.connect.cursor.execute')
    @patch('MySQLdb.connect.cursor')
    @patch('MySQLdb.connect')
    def test_execute(self, _connect, _cursor, _execute):
        new_engine = MysqlEngine(instance=self.ins1)
        execute_result = new_engine.execute(self.wf)
        self.assertIsInstance(execute_result, ResultSet)

    @patch.object(MysqlEngine, 'query')
    def test_server_version(self, _query):
        _query.return_value.rows = (('5.7.20', ), )
        new_engine = MysqlEngine(instance=self.ins1)
        server_version = new_engine.server_version
        self.assertTupleEqual(server_version, (5, 7, 20))

    @patch.object(MysqlEngine, 'query')
    def test_get_variables_not_filter(self, _query):
        new_engine = MysqlEngine(instance=self.ins1)
        new_engine.get_variables()
        _query.assert_called_once()

    @patch.object(MysqlEngine, 'query')
    def test_get_variables_filter(self, _query):
        new_engine = MysqlEngine(instance=self.ins1)
        new_engine.get_variables(variables=['binlog_format'])
        _query.assert_called()

    @patch.object(MysqlEngine, 'query')
    def test_set_variable(self, _query):
        new_engine = MysqlEngine(instance=self.ins1)
        new_engine.set_variable('binlog_format', 'ROW')
        _query.assert_called_once()