diff --git a/common/__init__.py b/common/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/common/enums.py b/common/enums.py new file mode 100644 index 0000000000000000000000000000000000000000..ea7bb3b019ea2d2b13f615a0eec258f5b1122b47 --- /dev/null +++ b/common/enums.py @@ -0,0 +1,181 @@ +from enum import Enum, unique + + +@unique +class Status_EN(str, Enum): + ANALYZING = 'analyzing' + REVIEWING = 'reviewing' + ACCEPTED = 'accepted' + REFUSED = 'refused' + + INIT = 'init' + WAITING = 'waiting' + PENDING = 'pending' + STARTING = 'starting' + RUNNING = 'running' + STOPPING = 'stopping' + + FINISH = 'finish' + STOPPED = 'stopped' + PAUSE = 'pause' + SKIP = 'skip' + CANCEL = 'cancel' + + SUCCESS = 'success' + FAIL = 'fail' + ERROR = 'error' + IGNORE = 'ignore' + + ONLINE = 'online' + OFFLINE = 'offline' + INSTALLING = 'installing' + UNINSTALLING = 'uninstalling' + + +@unique +class Status_CN(str, Enum): + ANALYZING = '分析中' + REVIEWING = '评审中' + ACCEPTED = '接受' + REFUSED = '拒绝' + + INIT = '新建' + WAITING = '等待中' + PENDING = '准备中' + STARTING = '启动中' + RUNNING = '运行中' + STOPPING = '停止中' + + FINISH = '完成' + STOPPED = '停止' + PAUSE = '暂停' + SKIP = '跳过' + CANCEL = '取消' + + SUCCESS = '执行成功' + FAIL = '执行失败' + ERROR = '执行出错' + IGNORE = '忽略失败' + + ONLINE = '在线' + OFFLINE = '离线' + INSTALLING = '安装中' + UNINSTALLING = '卸载中' + + +@unique +class Device_Type_EN(str, Enum): + UNLIMIT = 'unlimit' + VM = 'vm' + DOCKER = 'docker' + PHYSICS = 'physics' + + +@unique +class Device_Type_CN(str, Enum): + UNLIMIT = '不限制' + VM = '虚拟机' + DOCKER = 'docker' + PHYSICS = '物理机' + + +@unique +class Case_Run_Method(str, Enum): + MANUAL = 'manual' + AUTO = 'auto' + + +@unique +class Task_Run_Method(str, Enum): + MANUAL = 'manual' + AUTO = 'auto' + + +@unique +class Case_Run_Model(str, Enum): + SINGLE = 'single' + CLUSTER = 'cluster' + + +@unique +class Case_Level(int, Enum): + PRIORITY_0 = 0 + PRIORITY_1 = 1 + PRIORITY_2 = 2 + PRIORITY_3 = 3 + + +@unique +class Device_Arch(str, Enum): + X86 = 'x86' + ARCH64 = 'arch64' + RISCV = 'risc-v' + LOONGARCH = 'loongarch' + NOARCH = 'noarch' + OTHERS = 'others' + + +@unique +class Case_Type(str, Enum): + FUNCTIONAL = 'functional' + PERFORMANCE = 'performance' + STRESS = 'stress' + LOAD = 'load' + SECURITY = 'security' + COMPATIBILITY = 'compatibility' + OTHERS = 'others' + + +@unique +class User_Role(str, Enum): + ADMIN = 'admin' + SENIOR = 'senior' + JUNIOR = 'junior' + COMMON = 'common' + + +@unique +class User_Role_Review_Status(str, Enum): + INIT = 'init' + PASS = 'pass' + FAIL = 'fail' + + +@unique +class User_Role_Op_Method(str, Enum): + APPROVE = 'approve' + UPGRADE = 'upgrade' + DOWNGRADE = 'downgrade' + DELETE = 'delete' + + +@unique +class Tone_Job_State(str, Enum): + PENDING = 'pending' + RUNNING = 'running' + SUCCESS = 'success' + FAIL = 'fail' + STOP = 'stop' + SKIP = 'skip' + + +@unique +class Test_Type(str, Enum): + FUNCTIONAL = 'functional' + PERFORMANCE = 'performance' + + +@unique +class Case_Result(str, Enum): + SUCCESS = 'success' + FAIL = 'fail' + SKIP = 'skip' + + +@unique +class Track_Result(str, Enum): + NA = 'na' + INVALID = 'invalid' + NORMAL = 'normal' + DECLINE = 'decline' + INCREASE = 'increase' diff --git a/common/http.py b/common/http.py new file mode 100644 index 0000000000000000000000000000000000000000..912d212a75d185d5f2a48aed04587d8f7a1ca04e --- /dev/null +++ b/common/http.py @@ -0,0 +1,82 @@ +import asyncio +from json import loads + +from aiohttp import ClientSession +from sanic.response import json + +from common import token + + +def rsp(code=200, msg='success', data=None, paginate=None): + response = dict( + code=code, + msg=msg, + data=data + ) + if paginate: + response.update(paginate) + return json(response, ensure_ascii=False) + + +def http_headers(key): + timestamp, sign = token.common_sign(key=key) + headers = { + 'Content-Type': 'application/json;charset=UTF-8', + 'X-Sanic-Token': sign, + 'X-Sanic-Timestamp': str(timestamp) + } + return headers + + +def anolis_headers(key): + timestamp, sign, nonce = token.anolis_sign(key=key) + headers = { + 'Content-Type': 'application/json;charset=UTF-8', + 'Timestamp': str(timestamp), + 'Nonce': nonce, + 'Signature': sign + } + return headers + + +async def http_request(url, method, data=None, headers=None, verify_ssl=False, timeout=15, retry=3): + result = None + status = None + if headers is None: + headers = {'Content-Type': 'application/json;charset=UTF-8'} + async with ClientSession() as session: + while True: + try: + func = getattr(session, method) + async with func(url, data=data, headers=headers, timeout=timeout, verify_ssl=verify_ssl) as res: + result = await res.text() + status = res.status + break + except: + if retry > 0: + retry -= 1 + await asyncio.sleep(15) + continue + else: + break + try: + result = loads(result) + return status, result + except Exception as e: + return status, result + + +def handle_no_auth(_): + return rsp(code=401, msg='unauthorized') + + +async def read_file_content(url): + async with ClientSession() as session: + async with session.get(url) as resp: + if resp.status == 200: + res = b'' + async for data in resp.content.iter_chunked(1024): + res += data + return res + else: + return None diff --git a/common/static/temp.xlsx b/common/static/temp.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..3ded07dcf345a2ec041c18fe761fa3c4ca1c8611 Binary files /dev/null and b/common/static/temp.xlsx differ diff --git a/common/token.py b/common/token.py new file mode 100644 index 0000000000000000000000000000000000000000..7d73f1fce7b6b85ab49205944069eaaa7845cadf --- /dev/null +++ b/common/token.py @@ -0,0 +1,46 @@ +import time +import hmac +import base64 +import random +import string +import hashlib + + +def common_sign(key=None, timestamp=None): + if not timestamp: + timestamp = int(round(time.time() * 1000)) + if not key: + return timestamp, key + string_to_sign = '{}\n{}'.format(int(timestamp), key) + key_enc = key.encode('utf-8') + string_to_sign_enc = string_to_sign.encode('utf-8') + hmac_code = hmac.new(key_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest() + sign = base64.b64encode(hmac_code) + return timestamp, sign.decode('utf-8') + + +def gitee_sign(key=None, timestamp=None): + if not timestamp: + timestamp = int(round(time.time() * 1000)) + if not key: + return timestamp, key + string_to_sign = '{}\n{}'.format(int(timestamp), key) + key_enc = key.encode('utf-8') + string_to_sign_enc = string_to_sign.encode('utf-8') + hmac_code = hmac.new(key_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest() + sign = base64.b64encode(hmac_code) + return timestamp, sign.decode('utf-8') + + +def anolis_sign(key=None, timestamp=None, nonce=None): + if not timestamp: + timestamp = int(round(time.time() * 1000)) + if not nonce: + nonce = ''.join(random.sample(string.ascii_letters + string.digits, 24)) + if not key: + return timestamp, key, nonce + string_to_sign = '{}:{}:{}'.format(int(timestamp), nonce, key) + hash_obj = hashlib.sha256() + hash_obj.update(string_to_sign.encode('utf-8')) + sign = base64.b64encode(hash_obj.digest()) + return timestamp, sign.decode('utf-8'), nonce diff --git a/common/tone.py b/common/tone.py new file mode 100644 index 0000000000000000000000000000000000000000..02ba2d4653a666feb6f33de068156992fc83b518 --- /dev/null +++ b/common/tone.py @@ -0,0 +1,6 @@ +def fetch_cases(): + pass + + +def run_task(): + pass diff --git a/common/tone/__init__.py b/common/tone/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/common/tone/api.py b/common/tone/api.py new file mode 100644 index 0000000000000000000000000000000000000000..639cb3c807e7f1f586c47ca067407dc2bc3040aa --- /dev/null +++ b/common/tone/api.py @@ -0,0 +1,4 @@ +TONE_CREATE_JOB = 'api/job/create/' +TONE_SEARCH_CASE = 'api/case/get_case_list/' +TONE_JOB_QUERY = 'api/job/query/' +TONE_SUITE_QUERY = 'api/case/get_suite_all/' diff --git a/common/tools.py b/common/tools.py new file mode 100644 index 0000000000000000000000000000000000000000..a861a770b9e3d99adf8a4248308316365df501d9 --- /dev/null +++ b/common/tools.py @@ -0,0 +1,58 @@ +import os +import uuid +import time +import socket +import hashlib +import datetime + + +def new_id(): + s = str(os.getpid()) + '_' + uuid.uuid1().hex + return uuid.uuid3(uuid.NAMESPACE_OID, s).hex + + +def worker_id(port): + s = str(port) + '_' + uuid.uuid1().hex[-12:] + return uuid.uuid3(uuid.NAMESPACE_OID, s).hex + + +def md5(value): + if value: + value = hashlib.md5(value.encode('utf-8')).hexdigest() + return value + + +def datetime_toString(dt): + return dt.strftime("%Y-%m-%d %H:%M:%S") + + +def string_toDatetime(st): + return datetime.datetime.strptime(st, "%Y-%m-%d %H:%M:%S") + + +def string_toTimestamp(st): + return time.mktime(time.strptime(st, "%Y-%m-%d %H:%M:%S")) + + +def timestamp_toString(sp): + return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(sp)) + + +def datetime_toTimestamp(dt): + return time.mktime(dt.timetuple()) + + +def get_host(): + return socket.getfqdn(socket.gethostname()) + + +def get_ip(): + hostname = socket.getfqdn(socket.gethostname()) + try: + ip = socket.gethostbyname(hostname) + except socket.gaierror: + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.connect(('8.8.8.8', 1)) + ip = s.getsockname()[0] + s.close() + return ip diff --git a/common/utils/dict_compare.py b/common/utils/dict_compare.py new file mode 100644 index 0000000000000000000000000000000000000000..bba2392c4f24648cb3450bcfe4a8726d3e90f9bc --- /dev/null +++ b/common/utils/dict_compare.py @@ -0,0 +1,6 @@ +def is_A_contain_B(list_a, list_b): + dict_a = {i: 0 for i in list_a} + for item in list_b: + if f'{item}' not in dict_a: + return False + return True diff --git a/common/utils/excel.py b/common/utils/excel.py new file mode 100644 index 0000000000000000000000000000000000000000..3c480b0131006df0f38cbef4183d764b04b15afc --- /dev/null +++ b/common/utils/excel.py @@ -0,0 +1,47 @@ +import io +from datetime import datetime + +import numpy as np +import pandas as pd +from openpyxl.utils import get_column_letter + +try: + from io import BytesIO +except ImportError: + from cStringIO import StringIO as BytesIO + + +async def read_excel(content, columns_map): + df = pd.read_excel(io.BytesIO(content), keep_default_na=False) + new_fields = list(columns_map.values()) + df.rename(columns=columns_map, inplace=True) + df = df[new_fields] + return df.to_dict(orient='records') + + +async def write_excel(excel_content): + df = pd.DataFrame(excel_content) + bio = BytesIO() + writer = pd.ExcelWriter(bio, engine='openpyxl') + df.to_excel(writer, sheet_name='Sheet1', index=False) + __to_excel_auto_column_weight(df, writer, 'Sheet1') + writer.save() + return bio.getvalue() + + +def __to_excel_auto_column_weight(df, writer, sheet_name): + # 计算表头的字符宽度 + column_widths = ( + df.columns.to_series().apply(lambda x: len(x.encode('gbk'))).values + ) + # 计算每列的最大字符宽度 + max_widths = ( + df.astype(str).applymap(lambda x: len(x.encode('gbk'))).agg(max).values + ) + # 计算整体最大宽度 + widths = np.max([column_widths, max_widths], axis=0) + # 设置列宽 + worksheet = writer.sheets[sheet_name] + for i, width in enumerate(widths, 1): + # openpyxl引擎设置字符宽度时会减小0.5左右个字符,所以+2使左右都空出一个字宽 + worksheet.column_dimensions[get_column_letter(i)].width = width + 2