mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-13 04:30:28 +00:00
- all RAN code, CI code, configuration files, dockerfiles, in CSSL v1.0
- all deployment code (openshift, charts, ancillary files like shell
scripts), in MIT
- documentation in CC-BY-4.0
- exceptions might apply and are listed in NOTICE
- there is a new LICENSES folder with all licenses
- CONTRIBUTIONS.md has been updated accordingly
For automated changes based on OAI PL v1.1:
perl -i~ -0pe 's/\/\*.*Licensed to the OpenAirInterface.*openairinterface.org\n#?/\/*\n * SPDX-License-Identifier: LicenseRef-CSSL-1.0\n/s' **/*.{c,h,cpp}
perl -i~ -0pe 's/\/\*.*Licensed to the OpenAirInterface.*openairinterface.org\n#?/\/*\n * SPDX-License-Identifier: LicenseRef-CSSL-1.0\n/s' **/*.ts
perl -i~ -0pe 's/<!--.*Licensed to the OpenAirInterface.*openairinterface.org\n.*-->/<!-- SPDX-License-Identifier: LicenseRef-CSSL-1.0 -->/s' **/*.xml
The rest (cmake, files with missing license, cmake) manually.
142 lines
4.3 KiB
Python
142 lines
4.3 KiB
Python
# SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
|
|
|
import re
|
|
import os
|
|
import logging
|
|
from collections import deque
|
|
|
|
class Default:
|
|
def run(file, opt=None):
|
|
success = True
|
|
logs = []
|
|
with open(file, "r") as f:
|
|
for line in f.readlines():
|
|
result = re.search('[Aa]ssertion', line)
|
|
if result:
|
|
logs.append(line)
|
|
success = False
|
|
return success, "\n".join(logs)
|
|
|
|
class ContainsString:
|
|
def run(file, needle):
|
|
with open(file, "r") as f:
|
|
for line in f.readlines():
|
|
if re.search(needle, line):
|
|
return True, ""
|
|
return False, f"could not find '{needle}' in logs"
|
|
|
|
class LastLineContains:
|
|
def run(file, string):
|
|
with open(file, "r") as f:
|
|
last_line = deque(f, maxlen=1).pop()
|
|
success = string in last_line
|
|
log = "" if success else f"could not find '{string}' in last line"
|
|
return success, log
|
|
|
|
class EndsWithBye:
|
|
def run(file, option):
|
|
# no option: we ignore any
|
|
with open(file, "r") as f:
|
|
n = 0
|
|
for line in reversed(f.readlines()):
|
|
if re.search(r'^Bye.\n', line, re.MULTILINE) is not None:
|
|
return True, ""
|
|
n = n + 1
|
|
if n > 50: # if not found in last 50 lines, assume it does not exist
|
|
break
|
|
return False, "No Bye. message found, did not stop properly"
|
|
|
|
class RetxCheck():
|
|
def _parseList(s):
|
|
if not s:
|
|
return []
|
|
return [int(n) for n in s.split(",")]
|
|
|
|
def _get_ul_dl(s):
|
|
dl, ul = (None, None)
|
|
for o in s.split(";", 1):
|
|
if o.startswith("dl="):
|
|
dl = o[3:]
|
|
elif o.startswith("ul="):
|
|
ul = o[3:]
|
|
else:
|
|
raise ValueError(f"unrecognized option {s}: needs format '[ul=,dl=]X,Y,...[;ul=Z,V,...]'")
|
|
return dl, ul
|
|
|
|
def _parseRetxCheckers(options):
|
|
if not "=" in options:
|
|
dlul = RetxCheck._parseList(options)
|
|
return dlul, dlul
|
|
dl, ul = RetxCheck._get_ul_dl(options)
|
|
return RetxCheck._parseList(dl), RetxCheck._parseList(ul)
|
|
|
|
def _analyzeUeRetx(rounds, checkers, regex):
|
|
perc = list(0 for i in checkers) # results in %
|
|
stats = list(False for i in checkers) # status if succeeded
|
|
tmp = re.match(regex, rounds)
|
|
if tmp is None:
|
|
logging.error('_analyzeUeRetx: did not match regex for DL retx analysis')
|
|
return stats
|
|
retx_data = [float(x) for x in tmp.groups()]
|
|
for i in range(0, len(perc)):
|
|
#case where numerator > denumerator with denum ==0 is disregarded, cannot hapen in principle, will lead to 0%
|
|
perc[i] = 0 if (retx_data[i] == 0) else 100 * retx_data[i + 1] / retx_data[i]
|
|
#treating % > 100 , % > requirement
|
|
stats[i] = perc[i] <= 100 and perc[i] <= checkers[i]
|
|
return stats
|
|
|
|
def _filter_retx_rounds(l):
|
|
# map to round number if False, else None
|
|
l = [i+1 if x is False else None for i, x in enumerate(l)]
|
|
# filter out None
|
|
return [x for x in l if x is not None]
|
|
|
|
def run(file, options):
|
|
# aggregate statistics per UE
|
|
dlsch_ulsch_stats = {}
|
|
status = True
|
|
with open(file, "r") as f:
|
|
for line in f.readlines():
|
|
keys = {'dlsch_rounds','ulsch_rounds'}
|
|
for k in keys:
|
|
result = re.search(k, line)
|
|
if result is None:
|
|
continue
|
|
result = re.search('UE (?:RNTI )?([0-9a-f]{4})', line)
|
|
if result is None:
|
|
logging.error(f'did not find RNTI while matching key {k}')
|
|
status = False
|
|
continue
|
|
rnti = result.group(1)
|
|
if not rnti in dlsch_ulsch_stats:
|
|
dlsch_ulsch_stats[rnti] = {}
|
|
dlsch_ulsch_stats[rnti][k]=re.sub(r'^.*\]\s+', r'' , line.rstrip())
|
|
|
|
dl, ul = RetxCheck._parseRetxCheckers(options)
|
|
msgs = []
|
|
for ue in dlsch_ulsch_stats:
|
|
dlulstat = dlsch_ulsch_stats[ue]
|
|
|
|
for key in dlulstat:
|
|
msgs.append(dlulstat[key])
|
|
|
|
retx_dl = RetxCheck._analyzeUeRetx(dlulstat['dlsch_rounds'], dl, r'^.*dlsch_rounds\s+(\d+)\/(\d+)\/(\d+)\/(\d+),\s+dlsch_errors\s+(\d+)')
|
|
retx_ul = RetxCheck._analyzeUeRetx(dlulstat['ulsch_rounds'], ul, r'^.*ulsch_rounds\s+(\d+)\/(\d+)\/(\d+)\/(\d+),\s+ulsch_errors\s+(\d+)')
|
|
|
|
if False in retx_dl or False in retx_ul:
|
|
dlstr = RetxCheck._filter_retx_rounds(retx_dl)
|
|
ulstr = RetxCheck._filter_retx_rounds(retx_ul)
|
|
msg = f"UE {ue}: retx rounds"
|
|
if dlstr:
|
|
msg = f"{msg} DL {dlstr}"
|
|
if ulstr:
|
|
msg = f"{msg} UL {ulstr}"
|
|
msg = f"{msg} exceeded threshold"
|
|
msgs.append('!!! Failure: ' + msg)
|
|
logging.error(f'\u001B[1;37;41m {msg}\u001B[0m')
|
|
status = False
|
|
else:
|
|
msg = f"UE {ue} retransmissions within bounds"
|
|
logging.debug(msg)
|
|
return status, "\n".join(msgs)
|