# -*- encoding=utf-8 -*-
import os
import sys
import requests
import math
import re
import time
from bs4 import BeautifulSoup
from random import shuffle
import datetime
import pypinyin
import hashlib


def exchange(word):
    """
    中文转拼音
    :param word:
    :return:
    """
    s = ''
    for i in pypinyin.pinyin(word, style=pypinyin.NORMAL):
        s += ''.join(i)
    return s


def get_message(case_path, case_name):
    # 从注释中获取某个文件的 case tag 信息
    tags = []
    pyfile = open(case_path + os.sep + case_name + '.py', 'r', encoding='utf-8')
    lines = pyfile.readlines()
    for line in lines:
        if 'case_tag' in line:
            line = line.split('case_tag')[-1]
            # 对不规范的写法做一些处理，如中文分号, 中文逗号，多空格等。。
            line = re.sub(' ', '', line)
            line = line.replace('，', ',').replace(':', '').replace('：', '')
            line = line.strip().strip('\n')
            tags = line.split(',')
    pyfile.close()
    return tags


def get_all_dir(case_name, case_path):
    """
    :return: 获得需要执行的所有air的文件夹，同时创建单个log目录
    """
    case_list = []
    for dirs in os.listdir(case_path):
        isdir = os.path.join(case_path, dirs)
        if os.path.isdir(isdir) and isdir.endswith(".air"):
            air_name = dirs.replace('.air', '')
            if 'all' in case_name or air_name in case_name:
                # script = os.path.join(case_path, isdir)
                case_list.append(air_name)
    return case_list


def get_case_tag_list(case_path, cases):
    """
    遍历case目录下的文件，从文件中获取case tag,加入列表中
    如果想同时满足两个条件，用#分割
    """
    tagList = cases.split('#')
    env = os.environ['ENV']
    case_list = []
    for f in os.listdir(case_path):
        script = os.path.join(case_path, f)
        air_name = f.replace('.air', '')
        case_tags = get_message(script, air_name)
        flag = False
        for con in tagList:
            conList = con.split(',')
            if list(set(case_tags) & set(conList)):
                flag = True
            else:
                flag = False
                break
        if flag and (env in case_tags or env in ('sit', 'sita')):
            case_list.append(air_name)
    return case_list


def get_dir_exist(path, div_num):
    """
    判断报告文件夹是否存在
    """
    for i in range(div_num):
        test_path = path + os.sep + 'report_' + str(i+1)
        if not os.path.isdir(test_path):
            return False
    return True

def merge_report(div_num, report_path):
    """
    合并报告
    """
    total_cases = 0
    succ_cases = 0
    max_time = 0.0
    time_str = ''
    summary_r = open(report_path + os.sep + 'summary.html', 'r', encoding='utf-8')
    lines = summary_r.readlines()[:43]
    summary_r.close()
    summary_w = open(report_path + os.sep + 'summary.html', 'w', encoding='utf-8')
    for i in range(div_num):
        file = report_path + os.sep + 'report_' + str(i+1) + os.sep + 'summary.html'
        print(file)
        htmlfile = open(file, 'r', encoding='utf-8')
        htmlhandle = htmlfile.read()
        soup = BeautifulSoup(htmlhandle, 'html.parser')
        tables = soup.find_all("table")
        #print(tables)
        #第一个table存的是概要，第二个table存的是具体case。先读第一个表
        tab = tables[0]
        tr = tab.findAll('tr')[1]
        tds = tr.findAll('td')
        total_cases += int(tds[0].getText())
        succ_cases += int(tds[1].getText())
        minite = int(tds[2].getText().split('分')[0])
        second = int(tds[2].getText().split('分')[1].split('秒')[0])
        number = minite + second/60
        #print(number)
        if number > max_time:
            max_time = number
            time_str =  tds[2].getText()
        #再读第二个表
        tab = tables[1]
        trs = tab.findAll('tr')
        print(len(trs))
        for i in range(len(trs)):
            if i == 0:
                continue
            tds = trs[i].findAll('td')
            case_name = tds[0].getText()
            status = tds[1].getText()
            run_time  = tds[2].getText()
            if status == '成功':
                html = '''
        <tr width="600">
            <td class="details-col-elapsed"><a href='../log/%s/log.html' target='_blank'>%s</a></td>
            <td class="success">%s</td>
            <td class="details-col-elapsed">%s</td>
        </tr>''' % (case_name, case_name, status, run_time)
            else:
                html = '''
         <tr width="600">
            <td class="details-col-elapsed"><a href='../log/%s/log.html' target='_blank'>%s</a></td>
            <td class="fail">%s</td>
            <td class="details-col-elapsed">%s</td>
        </tr>''' % (case_name, case_name, status, run_time)
            lines.append(html)
            #print(html)
    pass_rate = round(succ_cases*100/total_cases, 2)
    summary = '''
<!--<div><h2>Test Statistics</h2></div>-->

    <table width="800">
        <caption><ul><li>测试概要</li></ul></caption>
        <tr  width="600">
            <th width="300" class='details-col-msg'>用例总数</th>
            <th class='details-col-msg'>成功数</th>
            <th class='details-col-msg'>运行用时</th>
            <th class='details-col-msg'>成功率</th>
        </tr>

        <tr width="600">
            <td class='details-col-elapsed'>%s</td>
            <td class='details-col-elapsed'>%s</td>
            <td class='details-col-elapsed'>%s</td>
            <td class="details-col-elapsed">%s</td>
        </tr>
    </table>
    </table>

 <!--<div><h2>Test detail</h2></div>-->
    <table width="800">
        <caption><ul><li>测试列表</li></ul></caption>
        <tr  width="600">
            <th width="300" class='details-col-msg'>用例名称</th>
            <th class='details-col-msg'>执行结果</th>
            <th class='details-col-msg'>执行时间(秒)</th>
        </tr>
        
''' % (total_cases, succ_cases, time_str, str(pass_rate))
    summary_w.write(summary)
    for line in lines:
        summary_w.write(line)
    end_html = '''
    </table>
<div><h2></h2></div>
</div>
</body>
</html>'''
    summary_w.write(end_html)
    summary_w.close()
    time_str = time_str.replace('分', 'm').replace('秒', 's')
    return total_cases, succ_cases, time_str, pass_rate


def get_mess_from_report(report_path):
    """
    从报告中获取运行case数
    :return:
    """
    htmlfile = open(report_path + os.sep + 'summary.html', 'r', encoding='utf-8')
    htmlhandle = htmlfile.read()
    soup = BeautifulSoup(htmlhandle, 'html.parser')
    tables = soup.find_all("table")
    # print(tables)
    # 第一个table存的是概要，第二个table存的是具体case。先读第一个表
    tab = tables[0]
    tr = tab.findAll('tr')[1]
    tds = tr.findAll('td')
    total_cases = int(tds[0].getText())
    succ_cases = int(tds[1].getText())
    time_str = tds[2].getText()
    time_str = time_str.replace('分', 'm').replace('秒', 's')
    if int(total_cases) != 0:
        pass_rate = round(succ_cases * 100 / total_cases, 2)
    else:
        pass_rate = 0.00
    htmlfile.close()
    return total_cases, succ_cases, time_str, pass_rate


def get(url):
    try:
        return requests.get(url)
    except requests.exceptions.ConnectionError:
        print('ConnectionError -- please wait 3 seconds')
        time.sleep(1)
    except requests.exceptions.ChunkedEncodingError:
        print('ChunkedEncodingError -- please wait 3 seconds')
        time.sleep(1)
    except:
        print('Unfortunitely -- An Unknow Error Happened, Please wait 3 seconds')
        time.sleep(1)


def call_back_atms(runenv, job_name, build_num, total, rate, run_time, pool_name, build_user):
    """
    回传数据到atms
    :return:
    """
    if runenv == 'autotestpreid':
        runenv_b = 1
    elif runenv == 'autotestsitid':
        runenv_b = 2
    else:
        runenv_b = 0
    url = "http://atms.baobaoshu.com/atms/rest/api/getJobResult?jobName=" + job_name + "&runenv=" + str(
        runenv_b) + "&buildNumber=" + str(build_num) + "&allSum=" + str(total) + "&passRate=" + str(
        rate) + "&execTime=" + run_time + "&poolName=" + pool_name + "&buildUser=" + build_user + "&p0Sum=0&p1Sum=0&p2Sum=0"
    print(url)
    response = get(url)
    print("回调atms返回结果")
    print(response.content.decode())


def call_back_cloud(runenv, pool_name, build_num, start, end, job_url, build_user, rate, oldrev, newrev):
    """
    回传到云平台
    :return:
    """
    if rate == 100.0:
        status = 'success'
    else:
        status = 'fail'

    url = "http://cloud.baobaoshu.com/cloud/buildautotest?type=" + \
          runenv + "&buildid=" + str(build_num) + "&pool=" + pool_name + \
          "&codeversion=" + str(newrev) + "&lastcversion=" + str(oldrev) + \
          "&starttime=" + str(start) + "&endtime=" + str(end) + "&status=" + status + \
          "&url=" + str(job_url) + "&autopassrate=" + str(rate) + "&user=" + str(build_user)
    print(url)
    response = get(url)
    print("回调云平台返回结果")
    print(response.content.decode())


def call_back_muse(deployid, cbtoken, build_user, pass_rate, job_url, build_num):
    """
    回调muse
    :return:
    """
    print("call back muse")
    result = 'Fail'
    if deployid != 'deployid' and cbtoken != 'cbtoken' and build_user == 'SYSTEM':
        if pass_rate == 100.0:
            result = 'Success'
        url = 'http://muse.baobaoshu.com/apiv1/deployment/ci-callback/'
        data = {'deployid': deployid, 'job_url': job_url, 'build_number': build_num, 'result': result, 'cbtoken': cbtoken}
        r = requests.post(url, data)
        print(data)
        print(r.content.decode())
    else:
        print('非远程触发')
        pass

def call_back_gitool(deployid, cbtoken, build_user, pass_rate, job_url, build_num,env_t):
    """
    回调gitool
    :return:
    """
    print("call back gitool")

    if deployid != 'deployid' and cbtoken == 'cbtoken' and build_user == 'SYSTEM':
        timestamp = str(int(time.time()))
        data = "gitool_autotest_api_token(- - #)" + timestamp

        sign_md5 = hashlib.md5()
        sign_md5.update(data.encode(encoding='utf-8'))
        data = sign_md5.hexdigest()
        verify_str = data + "_" + timestamp
        if pass_rate == 100.0:
            status = 'pass'
        else:
            status = 'failed'
        if env_t == 'on':
            url = 'http://gitool.plt.babytree-inc.com/gitool/update_online_autotest_result?'
        elif env_t == 'pre':
            url = 'http://gitool.plt.babytree-inc.com/gitool/update_pre_autotest_result?'
        elif env_t == 'sit':
            url = 'http://gitool.plt.babytree-inc.com/gitool/update_test_autotest_result?'

        url = url + "branch_id="+str(deployid)+"&result="+str(status)+"&result_url="+str(job_url)+"&detail_result=&"+"verify_str="+str(verify_str)
        print(url)
        response = get(url)
        print("回调gitool返回结果")
        print(response.content.decode())
    else:
        print('非远程触发')
        pass


if __name__ == '__main__':
    start = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
    print('start')
    case_path = os.path.abspath(".") + os.sep + 'air_case'
    report_path = os.path.abspath(".") + os.sep + 'report'
    # 第一个参数，case执行类型
    tag = sys.argv[1]
    # 想运行多个tag 用逗号分割。 想运行同时满足两种tag的用&号连接
    cases = sys.argv[2]
    # 第3个参数，日志数据等级
    log_level = sys.argv[3]
    # 第4个参数，子任务个数，或者 是 app运行模式
    num = sys.argv[4]
    # 第5个参数，子任务名或者 设备uid
    JobOrDevice = sys.argv[5]

    # pool名
    pool_name = sys.argv[6]
    runenv = sys.argv[7]
    job_name = sys.argv[8]
    build_num = sys.argv[9]
    job_url = sys.argv[10]
    build_user = exchange(sys.argv[11])

    oldrev = sys.argv[12]
    newrev = sys.argv[13]

    deployid = sys.argv[14]
    cbtoken = sys.argv[15]


    if runenv == 'autotestpreid':
        env_t = 'pre'
    elif runenv == 'autotestonlineid':
        env_t = 'on'
    elif runenv == 'autotestsitaid':
        env_t = 'sita'
    else:
        env_t = 'sit'
    os.environ['ENV'] = env_t

    # 如果num是 s,m,d 表示是运行app 用例
    if num in ('s', 'm', 'd'):
        cmd = 'python runner_app.py ' + JobOrDevice + ' ' + num + ' ' + tag + ' ' + cases + ' ' + log_level
        os.system(cmd)
        total_cases, succ_cases, run_time, pass_rate = get_mess_from_report(report_path)
    else:
        num = int(num)
        # 如果将任务数设置为1并且子任务名等于job名，就不分任务到子job，直接本机跑
        if num != 1 or JobOrDevice != job_name:
            case_list = cases.split(',')
            if tag == 'tag':
                case_list = get_case_tag_list(case_path, cases)
            if tag == 'all':
                case_list = get_all_dir(case_list, case_path)
            shuffle(case_list)
            length = len(case_list)
            if length >= num:
                div_num = num
            else:
                div_num = length
            print(div_num)
            for i in range(div_num):
                cmd = 'rd /s /q report\\report_' + str(i+1)
                os.system(cmd)
                one_list = case_list[math.floor(i / div_num * length):math.floor((i + 1) / div_num * length)]
                one_list_str = ",".join(one_list)
                print(one_list_str)
                url = 'http://jenkins.baobaoshu.com/view/Tools/job/' + JobOrDevice + '_' + str(i+1) + '/buildWithParameters?token=123456&tag=choose&cases=' + one_list_str + "&log_level=" + log_level + "&env=" + env_t + "&triger_job_name=" + job_name
                print(url)
                requests.get(url)
            # 等待1分钟
            time.sleep(60)
            # 判断报告传输是否完成
            while True:
                is_done = get_dir_exist(report_path, div_num)
                if is_done:
                    total_cases, succ_cases, run_time, pass_rate = merge_report(div_num, report_path)
                    break
                else:
                    time.sleep(5)
        else:
            run_url = str(job_url) + str(build_num) + os.sep + "artifact" + os.sep + "report" + os.sep + "summary.html"
            cmd = 'python runner.py ' + tag + ' ' + cases + ' ' + log_level + ' ' + env_t + ' ' + run_url
            os.system(cmd)
            total_cases, succ_cases, run_time, pass_rate = get_mess_from_report(report_path)
    end = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
    # 回传数据到gitool
    call_back_gitool(deployid, cbtoken, build_user, pass_rate, job_url, build_num, env_t)

    # 回传数据到muse
    call_back_muse(deployid, cbtoken, build_user, pass_rate, job_url, build_num)

    # 回传数据到atms
    call_back_atms(runenv, job_name, build_num, total_cases, pass_rate, run_time, pool_name, build_user)

    # 回传到云平台
    call_back_cloud(runenv, pool_name, build_num, start, end, job_url, build_user, pass_rate, oldrev, newrev)

    if pass_rate != 100.0:
        sys.exit(1)

