Skip to content

Commit

Permalink
doc: add tests catalog page
Browse files Browse the repository at this point in the history
Add a new section in the LTP documentation website, where we list all
tests which are available in LTP and supporting new API.

Acked-by: Cyril Hrubis <[email protected]>
Acked-by: Petr Vorel <[email protected]>
Signed-off-by: Andrea Cervesato <[email protected]>
  • Loading branch information
acerv committed Feb 6, 2025
1 parent a5a288f commit 1bf344a
Show file tree
Hide file tree
Showing 4 changed files with 282 additions and 4 deletions.
1 change: 1 addition & 0 deletions doc/.gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
html/
build/
_static/syscalls.rst
_static/tests.rst
syscalls.tbl
274 changes: 270 additions & 4 deletions doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import os
import re
import json
import socket
import urllib.request
import sphinx
Expand All @@ -17,6 +18,7 @@
author = 'Linux Test Project'
release = '1.0'
ltp_repo = 'https://github.com/linux-test-project/ltp'
ltp_repo_base_url = f"{ltp_repo}/tree/master"

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
Expand All @@ -25,7 +27,7 @@
'linuxdoc.rstKernelDoc',
'sphinxcontrib.spelling',
'sphinx.ext.autosectionlabel',
'sphinx.ext.extlinks'
'sphinx.ext.extlinks',
]

exclude_patterns = ["html*", '_static*']
Expand Down Expand Up @@ -138,7 +140,6 @@ def generate_syscalls_stats(_):
if error:
return

syscalls_base_url = f"{ltp_repo}/tree/master"
text = [
'Syscalls\n',
'--------\n\n',
Expand Down Expand Up @@ -176,7 +177,7 @@ def generate_syscalls_stats(_):
path = dirpath.replace('../', '')
name = match.group('name')

ltp_syscalls[name] = f'{syscalls_base_url}/{path}'
ltp_syscalls[name] = f'{ltp_repo_base_url}/{path}'

# compare kernel syscalls with LTP tested syscalls
syscalls = {}
Expand All @@ -186,7 +187,7 @@ def generate_syscalls_stats(_):

if kersc not in syscalls:
if kersc in white_list:
syscalls[kersc] = f'{syscalls_base_url}/{white_list[kersc]}'
syscalls[kersc] = f'{ltp_repo_base_url}/{white_list[kersc]}'
continue

syscalls[kersc] = None
Expand Down Expand Up @@ -256,10 +257,275 @@ def generate_syscalls_stats(_):
stats.writelines(text)


def _generate_tags_table(tags):
"""
Generate the tags table from tags hash.
"""
supported_url_ref = {
"linux-git": "https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=",
"linux-stable-git": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=",
"glibc-git": "https://sourceware.org/git/?p=glibc.git;a=commit;h=",
"musl-git": "https://git.musl-libc.org/cgit/musl/commit/src/linux/clone.c?id=",
"CVE": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-",
}

table = [
'.. list-table::',
' :header-rows: 1',
'',
' * - Tag',
' - Info',
]

for tag in tags:
tag_key = tag[0]
tag_val = tag[1]

tag_url = supported_url_ref.get(tag_key, None)
if tag_url:
tag_val = f'`{tag_val} <{tag_url}{tag_val}>`_'

table.extend([
f' * - {tag_key}',
f' - {tag_val}',
])

return table


def _generate_options_table(options):
"""
Generate the options table from the options hash.
"""
table = [
'.. list-table::',
' :header-rows: 1',
'',
' * - Option',
' - Description',
]

for opt in options:
if not isinstance(opt, list):
table.clear()
break

key = opt[0]
val = opt[2]

if key.endswith(':'):
key = key[:-1] if key.endswith(':') else key

key = f'-{key}'

table.extend([
f' * - {key}',
f' - {val}',
])

return table


def _generate_table_cell(key, values):
"""
Generate a cell which can be multiline if value is a list.
"""
cell = []

if len(values) > 1:
cell.extend([
f' * - {key}',
f' - | {values[0]}',
])

for item in values[1:]:
cell.append(f' | {item}')
else:
cell.extend([
f' * - {key}',
f' - {values[0]}',
])

return cell


def _generate_setup_table(keys):
"""
Generate the table with test setup configuration.
"""
exclude = [
# following keys are already handled
'options',
'runtime',
'timeout',
'fname',
'doc',
# following keys don't need to be shown
'child_needs_reinit',
'needs_checkpoints',
'forks_child',
'tags',
]
my_keys = {k: v for k, v in keys.items() if k not in exclude}
if len(my_keys) == 0:
return []

table = [
'.. list-table::',
' :header-rows: 1',
'',
' * - Key',
' - Value',
]

values = []

for key, value in my_keys.items():
if key in exclude:
continue

values.clear()

if key == 'ulimit':
for item in value:
values.append(f'{item[0]} : {item[1]}')
elif key == 'hugepages':
if len(value) == 1:
values.append(f'{value[0]}')
else:
values.append(f'{value[0]}, {value[1]}')
elif key == 'filesystems':
for v in value:
for item in v:
if isinstance(item, list):
continue

if item.startswith('.type'):
values.append(item.replace('.type=', ''))
elif key == "save_restore":
for item in value:
values.append(item[0])
else:
if isinstance(value, list):
values.extend(value)
else:
values.append(value)

table.extend(_generate_table_cell(key, values))

return table


def generate_test_catalog(_):
"""
Generate the test catalog from ltp.json metadata file.
"""
output = '_static/tests.rst'
metadata_file = '../metadata/ltp.json'
text = [
'.. warning::',
' The following catalog has been generated using LTP metadata',
' which is including only tests using the new :ref:`LTP C API`.',
''
]

metadata = None
with open(metadata_file, 'r', encoding='utf-8') as data:
metadata = json.load(data)

timeout_def = metadata['defaults']['timeout']

for test_name, conf in metadata['tests'].items():
text.extend([
f'{test_name}',
len(test_name) * '-'
])

# source url location
test_fname = conf.get('fname', None)
if test_fname:
text.extend([
'',
f"`source <{ltp_repo_base_url}/{test_fname}>`__",
''
])

# test description
desc = conf.get('doc', None)
if desc:
desc_text = []
for line in desc:
if line.startswith("[Description]"):
desc_text.append("**Description**")
elif line.startswith("[Algorithm]"):
desc_text.append("**Algorithm**")
else:
desc_text.append(line)

text.extend([
'\n'.join(desc_text),
])

# timeout information
timeout = conf.get('timeout', None)
if timeout:
text.extend([
'',
f'Test timeout is {timeout} seconds.',
])
else:
text.extend([
'',
f'Test timeout defaults is {timeout_def} seconds.',
])

# runtime information
runtime = conf.get('runtime', None)
if runtime:
text.extend([
f'Maximum runtime is {runtime} seconds.',
''
])
else:
text.append('')

# options information
opts = conf.get('options', None)
if opts:
text.append('')
text.extend(_generate_options_table(opts))
text.append('')

# tags information
tags = conf.get('tags', None)
if tags:
text.append('')
text.extend(_generate_tags_table(tags))
text.append('')

# parse struct tst_test content
text.append('')
text.extend(_generate_setup_table(conf))
text.append('')

# small separator between tests
text.extend([
'',
'.. raw:: html',
'',
' <hr>',
'',
])

with open(output, 'w+', encoding='utf-8') as new_tests:
new_tests.write('\n'.join(text))


def setup(app):
"""
Setup the current documentation, using self generated data and graphics
customizations.
"""
app.add_css_file('custom.css')
app.connect('builder-inited', generate_syscalls_stats)
app.connect('builder-inited', generate_test_catalog)
4 changes: 4 additions & 0 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
users/setup_tests
users/supported_systems
users/stats
users/test_catalog

.. toctree::
:maxdepth: 3
Expand Down Expand Up @@ -54,6 +55,9 @@ For users
:doc:`users/stats`
Some LTP statistics

:doc:`users/test_catalog`
The LTP test catalog

For developers
--------------

Expand Down
7 changes: 7 additions & 0 deletions doc/users/test_catalog.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.. SPDX-License-Identifier: GPL-2.0-or-later
Test catalog
============

.. include:: ../_static/tests.rst

0 comments on commit 1bf344a

Please sign in to comment.