blob: 87f994654557b32a7a6ec2d61bee568af63f6351 [file] [log] [blame]
############################################################################
#
# SPDX-License-Identifier: Apache-2.0
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership. The
# ASF licenses this file to you 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 logging
import os
import shutil
import subprocess
import time
from pathlib import Path
import pytest
from elftools.elf.elffile import ELFFile
def get_compile_paths(elf_file) -> str:
with open(elf_file, "rb") as f:
elf = ELFFile(f)
if not elf.has_dwarf_info():
return None
dwarf_info = elf.get_dwarf_info()
for CU in dwarf_info.iter_CUs():
top_DIE = CU.get_top_DIE()
if top_DIE and "DW_AT_comp_dir" in top_DIE.attributes:
path = top_DIE.attributes["DW_AT_comp_dir"].value.decode()
if "out" in path:
return path.split("cmake_out")[0]
return None
def run_command_in_subprocess(command):
return subprocess.Popen(
command,
shell=True,
text=True,
stderr=subprocess.DEVNULL,
stdout=subprocess.DEVNULL,
)
def _collect_gcda_dirs(device_conf, elf_path):
if device_conf["product"] == "sim":
compile_path = get_compile_paths(elf_path)
if compile_path is None:
pytest.skip("CI Package can't parse compile path")
return [compile_path], "/tmp/gcda", compile_path
else:
dump_path = "/share/gcda"
gcda_dir = ["{}/gcda".format(device_conf["9pfs_path"])]
for d in os.listdir(device_conf["9pfs_path"]):
if d.startswith("gcov_"):
gcda_dir.append("{}/{}".format(device_conf["9pfs_path"], d))
return gcda_dir, dump_path, None
@pytest.mark.dep_config("CONFIG_SYSTEM_GCOV", "CONFIG_FS_TMPFS")
@pytest.mark.cmd_check("gcov_main")
@pytest.mark.run(order=-2)
def test_gcov():
gcov_conf = pytest.task.get("gcov", {})
gcov_enable = gcov_conf.get("enable", False)
gcov_path = gcov_conf.get("gcov_path", "")
device_conf = pytest.task.get("device", {})
core_conf = pytest.task.get("cores", {})
main_core_conf = core_conf.get("core0", {})
elf_path = main_core_conf.get("elf_path", "")
""" Dump gcov data to the device_conf["9pfs_path"]/gcda directory """
if not gcov_enable:
pytest.skip("Gcov not enable")
if not os.path.exists(gcov_path):
pytest.skip(f"Gcov: gcov_path {gcov_path} no exits")
gcda_dir, dump_path, compile_path = _collect_gcda_dirs(device_conf, elf_path)
ret = pytest.product.sendCommand(f"echo > {dump_path}")
assert ret == 0
pytest.product.sendCommand(f"gcov -d {dump_path}", "Gcov dump complete")
gcovTimeout = 0
ret = 0
while gcovTimeout < 1200: # Wait for 20 minutes
ret = pytest.product.sendCommand(f"ls {dump_path}", "gcda")
if ret == 0:
break
time.sleep(30)
gcovTimeout += 30
if ret != 0:
print("Gcov dump may contain errors")
""" Use gcov.sh to analyse gcda,gcno file """
os.makedirs(gcov_conf["result_path"], exist_ok=True)
command = "{}/gcov.py -t {} -s {}/gcno -o {} --delete ".format(
gcov_conf["gcov_path"],
gcov_conf["toolchain"],
gcov_conf["gcov_path"],
gcov_conf["result_path"],
)
command += "-a "
for i in gcda_dir:
command += i + " "
print(f"Executing: {command}")
# Spawn the gcov script process
process = run_command_in_subprocess(command)
while process.poll() is None:
pytest.product.sendCommand("hello")
time.sleep(10)
assert process.wait() == 0
if compile_path:
shutil.rmtree(compile_path)
@pytest.mark.run(order=-1)
def test_system_mmleak():
gdb_conf = pytest.task.get("gdb", {})
if not gdb_conf or not gdb_conf["enable"] or not gdb_conf["enable_nxplugin"]:
pytest.skip("GDB Test No Enable")
def has_mmleak(dir):
mmleak = list(Path(dir).rglob("nuttx.mmleak"))
if mmleak:
logging.warning(f"Found mmleak files: {[str(f) for f in mmleak]}")
return False
return True
logging.info("GDB Check System Mmleak")
assert has_mmleak(gdb_conf["result"])