Initial code for log analysis

- we agreed to basically throw away the old log checker (as it is
  unmaintainable)
- now: provide list of analysis to do
  * all checkers in cls_log_analysis, can be unit tested (see also next
    commit)
  * looked up dynamically to simplify adding of new tests + config
  * configured with

      <analysis>
        <services>DESCRIPTION [DESCRIPTION...]</services>
        <service>DESCRIPTION</service>
        ...
      </analysis>

    where DESCRIPTION follows service=func[=options]:
    - service is name of service to check
    - func is function to call, which receives filename
    - option are arbitary options to pass to func
    <services> is whitespace delimited (so can take multiple service
    analysis definitions)
    <service> exists to allow service definitions with whitespace
    changes that would not work in <services>
- I initially planned to check return code, but most softmodems actually
  exit with non-zero return code, so this is still TODO
- Default analyzer (checking for assertions, ...) is always run if a
  service is listed
- checks for file size
- add unit tests
This commit is contained in:
Robert Schmidt
2026-02-26 14:17:28 +01:00
parent 03f56c10e7
commit fe464ec6d0
11 changed files with 257 additions and 32 deletions
+1
View File
@@ -16,6 +16,7 @@ To run individual unit tests, start them like so:
python tests/corenetwork.py -v
python tests/deployment.py -v
python tests/iperf-analysis.py -v
python tests/log-analysis.py -v
python tests/ping-iperf.py -v
python tests/pull-clean-int-registry.py -v
+14
View File
@@ -53,5 +53,19 @@ class TestAnalysis(unittest.TestCase):
# TODO this one is not found, the CI does not recover this??
#self.assertEqual(s['Data']['DL & UL scheduling timing'], ['17', '97', '159371', '1.14'])
def test_analze_services_no_service(self):
service_desc = {} # nothing to analyze
to_analyze = ["testserv"] # some service requested to be analyze that does not exist
status = cls_analysis.AnalyzeServices(self.html, service_desc, to_analyze)
self.assertFalse(status)
# TODO this does not work: we don't evaluate return codes yet
#def test_analze_service_exit_nonnull(self):
# service_desc = {}
# service_desc["testserv"] = {'returncode': 129, 'logfile': 'tests/log-analysis/empty.log'}
# to_analyze = ["testserv"] # some service requested to be analyze that does not exist
# status = cls_analysis.AnalyzeServices(self.html, service_desc, to_analyze)
# self.assertFalse(status)
if __name__ == '__main__':
unittest.main()
+39 -9
View File
@@ -16,7 +16,6 @@ import cls_oai_html
import cls_oaicitest
import cls_containerize
from cls_ci_helper import TestCaseCtx
import ran
import cls_cmd
class TestDeploymentMethods(unittest.TestCase):
@@ -39,7 +38,6 @@ class TestDeploymentMethods(unittest.TestCase):
self.html.testCaseId = "000000"
self.ci = cls_oaicitest.OaiCiTest()
self.cont = cls_containerize.Containerize()
self.ran = ran.RANManagement()
self.cont.yamlPath = ''
self.cont.ranAllowMerge = True
self.cont.ranBranch = ''
@@ -56,7 +54,7 @@ class TestDeploymentMethods(unittest.TestCase):
self.cont.yamlPath = 'tests/simple-dep/'
self.cont.deploymentTag = "noble"
deploy = self.cont.DeployObject(self.ctx, self.node, self.html)
undeploy = self.cont.UndeployObject(self.ctx, self.node, self.html, self.ran)
undeploy = self.cont.UndeployObject(self.ctx, self.node, self.html, [])
self.assertTrue(deploy)
self.assertTrue(undeploy)
@@ -79,7 +77,7 @@ class TestDeploymentMethods(unittest.TestCase):
stopB = self.cont.StopObject(self.ctx, self.node, self.html)
# should not undeploy anything (everything already stopped)
self.cont.services = None
undeployAll = self.cont.UndeployObject(self.ctx, self.node, self.html, self.ran)
undeployAll = self.cont.UndeployObject(self.ctx, self.node, self.html, [])
self.assertTrue(deploy)
self.assertFalse(stopC)
self.assertTrue(stopA)
@@ -92,7 +90,7 @@ class TestDeploymentMethods(unittest.TestCase):
old = self.cont.yamlPath
self.cont.yamlPath = 'tests/simple-fail/'
deploy = self.cont.DeployObject(self.ctx, self.node, self.html)
self.cont.UndeployObject(self.ctx, self.node, self.html, self.ran)
self.cont.UndeployObject(self.ctx, self.node, self.html, [])
self.assertFalse(deploy)
self.cont.yamlPath = old
@@ -101,7 +99,7 @@ class TestDeploymentMethods(unittest.TestCase):
old = self.cont.yamlPath
self.cont.yamlPath = 'tests/simple-fail-2svc/'
deploy = self.cont.DeployObject(self.ctx, self.node, self.html)
self.cont.UndeployObject(self.ctx, self.node, self.html, self.ran)
self.cont.UndeployObject(self.ctx, self.node, self.html, [])
self.assertFalse(deploy)
self.cont.yamlPath = old
@@ -110,7 +108,7 @@ class TestDeploymentMethods(unittest.TestCase):
self.cont.services = "oai-gnb"
self.cont.deploymentTag = 'develop-12345678'
deploy = self.cont.DeployObject(self.ctx, self.node, self.html)
undeploy = self.cont.UndeployObject(self.ctx, self.node, self.html, self.ran)
undeploy = self.cont.UndeployObject(self.ctx, self.node, self.html, [])
self.assertTrue(deploy)
self.assertTrue(undeploy)
@@ -119,7 +117,7 @@ class TestDeploymentMethods(unittest.TestCase):
self.cont.services = "oai-gnb oai-nr-ue"
self.cont.deploymentTag = 'develop-12345678'
deploy = self.cont.DeployObject(self.ctx, self.node, self.html)
undeploy = self.cont.UndeployObject(self.ctx, self.node, self.html, self.ran)
undeploy = self.cont.UndeployObject(self.ctx, self.node, self.html, [])
self.assertTrue(deploy)
self.assertTrue(undeploy)
@@ -130,7 +128,7 @@ class TestDeploymentMethods(unittest.TestCase):
deploy1 = self.cont.DeployObject(self.ctx, self.node, self.html)
self.cont.services = "oai-nr-ue"
deploy2 = self.cont.DeployObject(self.ctx, self.node, self.html)
undeploy = self.cont.UndeployObject(self.ctx, self.node, self.html, self.ran)
undeploy = self.cont.UndeployObject(self.ctx, self.node, self.html, [])
self.assertTrue(deploy1)
self.assertTrue(deploy2)
self.assertTrue(undeploy)
@@ -145,5 +143,37 @@ class TestDeploymentMethods(unittest.TestCase):
cmd.run(f"rm -rf {self.cont.eNBSourceCodePath}")
self.assertTrue(ws)
def test_undeploy_loganalysis(self):
self.cont.yamlPath = 'yaml_files/5g_rfsimulator_tdd_dora'
self.cont.services = "oai-gnb"
self.cont.deploymentTag = 'develop-12345678'
deploy = self.cont.DeployObject(self.ctx, self.node, self.html)
analyze = ["oai-gnb"]
undeploy = self.cont.UndeployObject(self.ctx, self.node, self.html, analyze)
self.assertTrue(deploy)
self.assertTrue(undeploy)
def test_undeploy_multi_loganalysis(self):
self.cont.yamlPath = 'yaml_files/5g_rfsimulator_tdd_dora'
self.cont.services = "oai-gnb"
self.cont.deploymentTag = 'develop-12345678'
deploy = self.cont.DeployObject(self.ctx, self.node, self.html)
analyze = ["oai-gnb", "oai-gnb=ContainsString=NOTFOUND"]
undeploy = self.cont.UndeployObject(self.ctx, self.node, self.html, analyze)
self.assertTrue(deploy)
self.assertFalse(undeploy)
# TODO this does not work: we don't evaluate return codes yet
#def test_undeploy_rc_nonnull(self):
# # fails reliably
# old = self.cont.yamlPath
# self.cont.yamlPath = 'tests/simple-fail/'
# deploy = self.cont.DeployObject(self.ctx, self.node, self.html)
# # should be false because wrong exit code
# undeploy = self.cont.UndeployObject(self.ctx, self.node, self.html, ["test"])
# self.assertFalse(deploy)
# self.assertFalse(undeploy)
# self.cont.yamlPath = old
if __name__ == '__main__':
unittest.main()
+26
View File
@@ -0,0 +1,26 @@
import sys
import logging
logging.basicConfig(
level=logging.DEBUG,
stream=sys.stdout,
format="[%(asctime)s] %(levelname)8s: %(message)s"
)
import os
import unittest
sys.path.append('./') # to find OAI imports below
import cls_loganalysis
class TestLogAnalysis(unittest.TestCase):
def test_no_file(self):
f = "/total/fantasy/path/file.log"
result, _ = cls_loganalysis.Default.run(f, None)
self.assertFalse(result)
def test_no_error(self):
f = "tests/log-analysis/empty.log"
result, _ = cls_loganalysis.Default.run(f, None)
self.assertTrue(result)
if __name__ == '__main__':
unittest.main()