diff --git a/flight_recoder/analysis_flight.py b/flight_recorder/flight_recorder_analyze/analysis_flight.py similarity index 100% rename from flight_recoder/analysis_flight.py rename to flight_recorder/flight_recorder_analyze/analysis_flight.py diff --git a/flight_recoder/check_path.py b/flight_recorder/flight_recorder_analyze/check_path.py similarity index 100% rename from flight_recoder/check_path.py rename to flight_recorder/flight_recorder_analyze/check_path.py diff --git a/flight_recoder/flight_recoder.md b/flight_recorder/flight_recorder_analyze/flight_recorder.md similarity index 100% rename from flight_recoder/flight_recoder.md rename to flight_recorder/flight_recorder_analyze/flight_recorder.md diff --git a/flight_recorder/test/__init__.py b/flight_recorder/test/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/flight_recorder/test/run_st.py b/flight_recorder/test/run_st.py new file mode 100644 index 0000000000000000000000000000000000000000..b8acfde729f7ca2a4b519c1d140357a0c67fe0af --- /dev/null +++ b/flight_recorder/test/run_st.py @@ -0,0 +1,94 @@ +# Copyright (c) 2025-2025 Huawei Technologies Co., Ltd. + +import datetime +import logging +import os +import subprocess +import sys +import threading + +stop_print_thread = False + + +def print_stout(output): + while True: + line = output.readline().strip() + if line: + logging.info(line) + global stop_print_thread + if stop_print_thread: + break + + +def stop_stout_threads(thread_list): + global stop_print_thread + stop_print_thread = True + for stout_thread in thread_list: + if stout_thread.is_alive(): + stout_thread.join() + + +def start_st_process(module_name): + st_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), "st", module_name) + cmd = ["python3", "-m", "pytest", "-s", st_path] + process = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + stout_thread = threading.Thread(target=print_stout, args=(process.stdout,)) + stout_thread.start() + return process, stout_thread + + +def stop_st_process(process_list): + for process in process_list: + if process.poll() is None: + process.terminate() + process.wait() + + +def run_st(module_choice): + timeout = 3600 + modules = ["flight_recoder_analyze"] + if module_choice != "all": + modules = [module_choice] + process_list = [] + thread_list = [] + for module in modules: + process, stout_thread = start_st_process(module) + process_list.append(process) + thread_list.append(stout_thread) + + success, failed = True, False + start_time = datetime.datetime.utcnow() + while process_list: + duration = datetime.datetime.utcnow() - start_time + if duration.total_seconds() >= timeout: + logging.error("run st use case timeout.") + stop_stout_threads(thread_list) + stop_st_process(process_list) + return failed + for process in process_list: + if process.poll() is None: + continue + if process.returncode == 0: + process_list.remove(process) + continue + stop_stout_threads(thread_list) + stop_st_process(process_list) + return failed + stop_stout_threads(thread_list) + return success + + +if __name__ == "__main__": + logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') + if '--module' in sys.argv: + module_index = sys.argv.index("--module") + 1 + module = sys.argv[module_index] + else: + module = "all" + st_success = run_st(module) + if st_success: + logging.info("run st successfully.") + sys.exit(0) + else: + logging.error("run st failed.") + sys.exit(1) \ No newline at end of file diff --git a/flight_recorder/test/run_ut.sh b/flight_recorder/test/run_ut.sh new file mode 100644 index 0000000000000000000000000000000000000000..4f0d8caac33596e6b90a2936d4acf52108e4c237 --- /dev/null +++ b/flight_recorder/test/run_ut.sh @@ -0,0 +1,50 @@ +#!/bin/bash +# This script is used to run ut and st testcase. +# Copyright Huawei Technologies Co., Ltd. 2021-2022. All rights reserved. +CUR_DIR=$(dirname $(readlink -f $0)) +TOP_DIR=$(readlink -f ${CUR_DIR}/..) +TEST_DIR=${TOP_DIR}/"test" +SRC_DIR=${TOP_DIR}/"src" +ret=0 + +clean() { + cd ${TEST_DIR} + if [ -e ${TEST_DIR}/coverage.xml ]; then + rm coverage.xml + echo "remove last coverage.xml success" + fi + cd - +} + +run_test_cpp() { + cd . +} + +run_test_python() { + python3 --version + #pip3 install pytest "pandas>=2.2" + export PYTHONPATH=${TOP_DIR}:${PYTHONPATH} + python3 -m coverage run --branch --source ${TOP_DIR}/'flight_recoder_analyze' -m pytest ${TEST_DIR}/ut + + if [ $? -ne 0 ]; then + echo "UT Failure" + exit 1 + fi + + python3 -m coverage report -m + python3 -m coverage xml -o ${TEST_DIR}/coverage.xml +} + +run_test() { + run_test_cpp + run_test_python +} + +main() { + cd ${TEST_DIR} + clean + run_test + echo "UT Success" +} + +main \ No newline at end of file diff --git a/flight_recorder/test/st/__init__.py b/flight_recorder/test/st/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/flight_recorder/test/st/utils.py b/flight_recorder/test/st/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..3cc4eea180778fccdcdb21b4c103733f60ef7704 --- /dev/null +++ b/flight_recorder/test/st/utils.py @@ -0,0 +1,64 @@ +# Copyright (c) 2025-2025 Huawei Technologies Co., Ltd. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import subprocess +import logging + +COMMAND_SUCCESS = 0 + + +def execute_cmd(cmd): + logging.info('Execute command:%s' % " ".join(cmd)) + completed_process = subprocess.run(cmd, shell=False, stderr=subprocess.PIPE) + if completed_process.returncode != COMMAND_SUCCESS: + logging.error(completed_process.stderr.decode()) + return completed_process.returncode + + +def check_column_actual(actual_columns, expected_columns, context): + """检查实际列名是否与预期列名一致""" + for col in expected_columns: + if col not in actual_columns: + logging.error(f"在 {context} 中未找到预期列名: {col}") + return False + return True + + +def check_row(df, expected_columns, numeric_columns): + """检查数据框中Metric列数据类型和指定列数据是否为数字""" + # 检查Metric列的数据类型是否为字符串 + for row_index in df.index: + try: + value = df.at[row_index, 'Metric'] + if not isinstance(value, str): + logging.error(f"在Metric列的第{row_index}行,值 '{value}' 不是字符串类型") + return False + except KeyError: + logging.error(f"数据框中不存在 'Metric' 列") + return False + + # 检查其他列的数据是否为数字 + for column in numeric_columns: + if column not in df.columns: + logging.error(f"数据框中不存在 {column} 列") + continue + for row_index in df.index: + try: + cell_value = df.at[row_index, column] + float(cell_value) + except (ValueError, KeyError): + logging.error( + f"在 {column} 列的第 {row_index} 行,值 {cell_value} 不是有效的数字") + return False + return True \ No newline at end of file