Browse Source

Merge pull request #2612 from citrin/luacov-merge

Speedup lua coverage collecting for functional test
tags/1.8.2
Vsevolod Stakhov 5 years ago
parent
commit
7054a882a1
No account linked to committer's email address
3 changed files with 74 additions and 29 deletions
  1. 4
    0
      .circleci/config.yml
  2. 5
    1
      .drone.yml
  3. 65
    28
      test/functional/lib/rspamd.py

+ 4
- 0
.circleci/config.yml View File

@@ -113,6 +113,10 @@ jobs:
- run: cd ../build
# see coverage notice in "build" stage
- run: set +e; RSPAMD_INSTALLROOT=../install sudo -E bash -c "umask 0000; robot -x xunit.xml --exclude isbroken ../project/test/functional/cases"; echo "export RETURN_CODE=$?" >> $BASH_ENV
# luacov-coveralls reads luacov.stats.out generated by functional tests
# (see collect_lua_coverage() in test/functional/lib/rspamd.py)
# and writes json report for coveralls.io
- run: luacov-coveralls -o lua_coverage_report.json --dryrun

- *capture_coverage_data


+ 5
- 1
.drone.yml View File

@@ -121,10 +121,14 @@ pipeline:
- cd /rspamd/build
# extract coverage data for C code from .gcda files and save it in a format suitable for coveralls.io
- $CI_WORKSPACE/test/tools/gcov_coveralls.py --exclude test --prefix /rspamd/build --prefix $CI_WORKSPACE --out coverage.c.json
# luacov-coveralls reads luacov.stats.out generated by functional tests
# (see collect_lua_coverage() in test/functional/lib/rspamd.py)
# and writes json report for coveralls.io
- luacov-coveralls -o coverage.functional.lua.json --dryrun
# * merge coverage for C and Lua code
# * remove prefixes from absolute paths (in luacov-coveralls files), filter test, contrib, e. t.c
# * upload report to coveralls.io
- $CI_WORKSPACE/test/tools/merge_coveralls.py --root $CI_WORKSPACE --input coverage.c.json unit_test_lua.json lua_coverage_report.json --token=$COVERALLS_REPO_TOKEN
- $CI_WORKSPACE/test/tools/merge_coveralls.py --root $CI_WORKSPACE --input coverage.c.json unit_test_lua.json coverage.functional.lua.json --token=$COVERALLS_REPO_TOKEN
when:
branch: master
# don't send coverage report for pull request

+ 65
- 28
test/functional/lib/rspamd.py View File

@@ -10,7 +10,6 @@ import signal
import socket
import sys
import tempfile
import subprocess
from robot.libraries.BuiltIn import BuiltIn
from robot.api import logger

@@ -296,41 +295,79 @@ def python3_which(cmd, mode=os.F_OK | os.X_OK, path=None):
return None


def _merge_luacov_stats(statsfile, coverage):
"""
Reads a coverage stats file written by luacov and merges coverage data to
'coverage' dict: { src_file: hits_list }

Format of the file defined in:
https://github.com/keplerproject/luacov/blob/master/src/luacov/stats.lua
"""
with open(statsfile, 'rb') as fh:
while True:
# max_line:filename
line = fh.readline().rstrip()
if not line:
break

max_line, src_file = line.split(':')
counts = [int(x) for x in fh.readline().split()]
assert len(counts) == int(max_line)

if src_file in coverage:
# enlarge list if needed: lenght of list in different luacov.stats.out files may differ
old_len = len(coverage[src_file])
new_len = len(counts)
if new_len > old_len:
coverage[src_file].extend([0] * (new_len - old_len))
# sum execution counts for each line
for l, exe_cnt in enumerate(counts):
coverage[src_file][l] += exe_cnt
else:
coverage[src_file] = counts


def _dump_luacov_stats(statsfile, coverage):
"""
Saves data to the luacov stats file. Existing file is overwritted if exists.
"""
src_files = sorted(coverage)

with open(statsfile, 'wb') as fh:
for src in src_files:
stats = " ".join(str(n) for n in coverage[src])
fh.write("%s:%s\n%s\n" % (len(coverage[src]), src, stats))


# File used by luacov to collect coverage stats
LUA_STATSFILE = "luacov.stats.out"


def collect_lua_coverage():
if python3_which("luacov-coveralls") is None:
logger.info("luacov-coveralls not found, will not collect Lua coverage")
return
"""
Merges ${TMPDIR}/*.luacov.stats.out into luacov.stats.out

Example:
| Collect Lua Coverage |
"""
# decided not to do optional coverage so far
#if not 'ENABLE_LUA_COVERAGE' in os.environ['HOME']:
# logger.info("ENABLE_LUA_COVERAGE is not present in env, will not collect Lua coverage")
# return

current_directory = os.getcwd()
report_file = current_directory + "/lua_coverage_report.json"
old_report = current_directory + "/lua_coverage_report.json.old"

tmp_dir = BuiltIn().get_variable_value("${TMPDIR}")
coverage_files = glob.glob('%s/*.luacov.stats.out' % (tmp_dir))

for stat_file in coverage_files:
shutil.move(stat_file, "luacov.stats.out")
# logger.console("statfile: " + stat_file)

if (os.path.isfile(report_file)):
shutil.move(report_file, old_report)
p = subprocess.Popen(["luacov-coveralls", "-o", report_file, "-j", old_report, "--merge", "--dryrun"],
stdout = subprocess.PIPE, stderr= subprocess.PIPE)
output,error = p.communicate()
coverage = {}
input_files = []

logger.info("luacov-coveralls stdout: " + output)
logger.info("luacov-coveralls stderr: " + error)
os.remove(old_report)
else:
p = subprocess.Popen(["luacov-coveralls", "-o", report_file, "--dryrun"], stdout = subprocess.PIPE, stderr= subprocess.PIPE)
output,error = p.communicate()

logger.info("luacov-coveralls stdout: " + output)
logger.info("luacov-coveralls stderr: " + error)
os.remove("luacov.stats.out")
for f in glob.iglob("%s/*.luacov.stats.out" % tmp_dir):
_merge_luacov_stats(f, coverage)
input_files.append(f)

if input_files:
if os.path.isfile(LUA_STATSFILE):
_merge_luacov_stats(LUA_STATSFILE, coverage)
_dump_luacov_stats(LUA_STATSFILE, coverage)
logger.info("%s merged into %s" % (", ".join(input_files), LUA_STATSFILE))
else:
logger.info("no *.luacov.stats.out files found in %s" % tmp_dir)

Loading…
Cancel
Save