Skip to content

Commit 1bf344a

Browse files
committed
doc: add tests catalog page
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]>
1 parent a5a288f commit 1bf344a

File tree

4 files changed

+282
-4
lines changed

4 files changed

+282
-4
lines changed

doc/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
html/
22
build/
33
_static/syscalls.rst
4+
_static/tests.rst
45
syscalls.tbl

doc/conf.py

Lines changed: 270 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import os
77
import re
8+
import json
89
import socket
910
import urllib.request
1011
import sphinx
@@ -17,6 +18,7 @@
1718
author = 'Linux Test Project'
1819
release = '1.0'
1920
ltp_repo = 'https://github.com/linux-test-project/ltp'
21+
ltp_repo_base_url = f"{ltp_repo}/tree/master"
2022

2123
# -- General configuration ---------------------------------------------------
2224
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
@@ -25,7 +27,7 @@
2527
'linuxdoc.rstKernelDoc',
2628
'sphinxcontrib.spelling',
2729
'sphinx.ext.autosectionlabel',
28-
'sphinx.ext.extlinks'
30+
'sphinx.ext.extlinks',
2931
]
3032

3133
exclude_patterns = ["html*", '_static*']
@@ -138,7 +140,6 @@ def generate_syscalls_stats(_):
138140
if error:
139141
return
140142

141-
syscalls_base_url = f"{ltp_repo}/tree/master"
142143
text = [
143144
'Syscalls\n',
144145
'--------\n\n',
@@ -176,7 +177,7 @@ def generate_syscalls_stats(_):
176177
path = dirpath.replace('../', '')
177178
name = match.group('name')
178179

179-
ltp_syscalls[name] = f'{syscalls_base_url}/{path}'
180+
ltp_syscalls[name] = f'{ltp_repo_base_url}/{path}'
180181

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

187188
if kersc not in syscalls:
188189
if kersc in white_list:
189-
syscalls[kersc] = f'{syscalls_base_url}/{white_list[kersc]}'
190+
syscalls[kersc] = f'{ltp_repo_base_url}/{white_list[kersc]}'
190191
continue
191192

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

258259

260+
def _generate_tags_table(tags):
261+
"""
262+
Generate the tags table from tags hash.
263+
"""
264+
supported_url_ref = {
265+
"linux-git": "https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=",
266+
"linux-stable-git": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=",
267+
"glibc-git": "https://sourceware.org/git/?p=glibc.git;a=commit;h=",
268+
"musl-git": "https://git.musl-libc.org/cgit/musl/commit/src/linux/clone.c?id=",
269+
"CVE": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-",
270+
}
271+
272+
table = [
273+
'.. list-table::',
274+
' :header-rows: 1',
275+
'',
276+
' * - Tag',
277+
' - Info',
278+
]
279+
280+
for tag in tags:
281+
tag_key = tag[0]
282+
tag_val = tag[1]
283+
284+
tag_url = supported_url_ref.get(tag_key, None)
285+
if tag_url:
286+
tag_val = f'`{tag_val} <{tag_url}{tag_val}>`_'
287+
288+
table.extend([
289+
f' * - {tag_key}',
290+
f' - {tag_val}',
291+
])
292+
293+
return table
294+
295+
296+
def _generate_options_table(options):
297+
"""
298+
Generate the options table from the options hash.
299+
"""
300+
table = [
301+
'.. list-table::',
302+
' :header-rows: 1',
303+
'',
304+
' * - Option',
305+
' - Description',
306+
]
307+
308+
for opt in options:
309+
if not isinstance(opt, list):
310+
table.clear()
311+
break
312+
313+
key = opt[0]
314+
val = opt[2]
315+
316+
if key.endswith(':'):
317+
key = key[:-1] if key.endswith(':') else key
318+
319+
key = f'-{key}'
320+
321+
table.extend([
322+
f' * - {key}',
323+
f' - {val}',
324+
])
325+
326+
return table
327+
328+
329+
def _generate_table_cell(key, values):
330+
"""
331+
Generate a cell which can be multiline if value is a list.
332+
"""
333+
cell = []
334+
335+
if len(values) > 1:
336+
cell.extend([
337+
f' * - {key}',
338+
f' - | {values[0]}',
339+
])
340+
341+
for item in values[1:]:
342+
cell.append(f' | {item}')
343+
else:
344+
cell.extend([
345+
f' * - {key}',
346+
f' - {values[0]}',
347+
])
348+
349+
return cell
350+
351+
352+
def _generate_setup_table(keys):
353+
"""
354+
Generate the table with test setup configuration.
355+
"""
356+
exclude = [
357+
# following keys are already handled
358+
'options',
359+
'runtime',
360+
'timeout',
361+
'fname',
362+
'doc',
363+
# following keys don't need to be shown
364+
'child_needs_reinit',
365+
'needs_checkpoints',
366+
'forks_child',
367+
'tags',
368+
]
369+
my_keys = {k: v for k, v in keys.items() if k not in exclude}
370+
if len(my_keys) == 0:
371+
return []
372+
373+
table = [
374+
'.. list-table::',
375+
' :header-rows: 1',
376+
'',
377+
' * - Key',
378+
' - Value',
379+
]
380+
381+
values = []
382+
383+
for key, value in my_keys.items():
384+
if key in exclude:
385+
continue
386+
387+
values.clear()
388+
389+
if key == 'ulimit':
390+
for item in value:
391+
values.append(f'{item[0]} : {item[1]}')
392+
elif key == 'hugepages':
393+
if len(value) == 1:
394+
values.append(f'{value[0]}')
395+
else:
396+
values.append(f'{value[0]}, {value[1]}')
397+
elif key == 'filesystems':
398+
for v in value:
399+
for item in v:
400+
if isinstance(item, list):
401+
continue
402+
403+
if item.startswith('.type'):
404+
values.append(item.replace('.type=', ''))
405+
elif key == "save_restore":
406+
for item in value:
407+
values.append(item[0])
408+
else:
409+
if isinstance(value, list):
410+
values.extend(value)
411+
else:
412+
values.append(value)
413+
414+
table.extend(_generate_table_cell(key, values))
415+
416+
return table
417+
418+
419+
def generate_test_catalog(_):
420+
"""
421+
Generate the test catalog from ltp.json metadata file.
422+
"""
423+
output = '_static/tests.rst'
424+
metadata_file = '../metadata/ltp.json'
425+
text = [
426+
'.. warning::',
427+
' The following catalog has been generated using LTP metadata',
428+
' which is including only tests using the new :ref:`LTP C API`.',
429+
''
430+
]
431+
432+
metadata = None
433+
with open(metadata_file, 'r', encoding='utf-8') as data:
434+
metadata = json.load(data)
435+
436+
timeout_def = metadata['defaults']['timeout']
437+
438+
for test_name, conf in metadata['tests'].items():
439+
text.extend([
440+
f'{test_name}',
441+
len(test_name) * '-'
442+
])
443+
444+
# source url location
445+
test_fname = conf.get('fname', None)
446+
if test_fname:
447+
text.extend([
448+
'',
449+
f"`source <{ltp_repo_base_url}/{test_fname}>`__",
450+
''
451+
])
452+
453+
# test description
454+
desc = conf.get('doc', None)
455+
if desc:
456+
desc_text = []
457+
for line in desc:
458+
if line.startswith("[Description]"):
459+
desc_text.append("**Description**")
460+
elif line.startswith("[Algorithm]"):
461+
desc_text.append("**Algorithm**")
462+
else:
463+
desc_text.append(line)
464+
465+
text.extend([
466+
'\n'.join(desc_text),
467+
])
468+
469+
# timeout information
470+
timeout = conf.get('timeout', None)
471+
if timeout:
472+
text.extend([
473+
'',
474+
f'Test timeout is {timeout} seconds.',
475+
])
476+
else:
477+
text.extend([
478+
'',
479+
f'Test timeout defaults is {timeout_def} seconds.',
480+
])
481+
482+
# runtime information
483+
runtime = conf.get('runtime', None)
484+
if runtime:
485+
text.extend([
486+
f'Maximum runtime is {runtime} seconds.',
487+
''
488+
])
489+
else:
490+
text.append('')
491+
492+
# options information
493+
opts = conf.get('options', None)
494+
if opts:
495+
text.append('')
496+
text.extend(_generate_options_table(opts))
497+
text.append('')
498+
499+
# tags information
500+
tags = conf.get('tags', None)
501+
if tags:
502+
text.append('')
503+
text.extend(_generate_tags_table(tags))
504+
text.append('')
505+
506+
# parse struct tst_test content
507+
text.append('')
508+
text.extend(_generate_setup_table(conf))
509+
text.append('')
510+
511+
# small separator between tests
512+
text.extend([
513+
'',
514+
'.. raw:: html',
515+
'',
516+
' <hr>',
517+
'',
518+
])
519+
520+
with open(output, 'w+', encoding='utf-8') as new_tests:
521+
new_tests.write('\n'.join(text))
522+
523+
259524
def setup(app):
260525
"""
261526
Setup the current documentation, using self generated data and graphics
262527
customizations.
263528
"""
264529
app.add_css_file('custom.css')
265530
app.connect('builder-inited', generate_syscalls_stats)
531+
app.connect('builder-inited', generate_test_catalog)

doc/index.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
users/setup_tests
1212
users/supported_systems
1313
users/stats
14+
users/test_catalog
1415

1516
.. toctree::
1617
:maxdepth: 3
@@ -54,6 +55,9 @@ For users
5455
:doc:`users/stats`
5556
Some LTP statistics
5657

58+
:doc:`users/test_catalog`
59+
The LTP test catalog
60+
5761
For developers
5862
--------------
5963

doc/users/test_catalog.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.. SPDX-License-Identifier: GPL-2.0-or-later
2+
3+
Test catalog
4+
============
5+
6+
.. include:: ../_static/tests.rst
7+

0 commit comments

Comments
 (0)