Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-imagine TestPlan as a single TestPlanSessionTemplate that is run against one or more Constellations #407

Merged
merged 2 commits into from
Oct 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 16 additions & 20 deletions src/feditest/cli/commands/convert_transcript.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,13 @@
from argparse import ArgumentParser, Namespace, _SubParsersAction

from feditest.reporting import warning
from feditest.testruntranscript import (
JsonTestRunTranscriptSerializer,
MultifileRunTranscriptSerializer,
SummaryTestRunTranscriptSerializer,
TapTestRunTranscriptSerializer,
TestRunTranscript
)
from feditest.testruntranscript import TestRunTranscript
from feditest.testruntranscriptserializer.json import JsonTestRunTranscriptSerializer
from feditest.testruntranscriptserializer.html import HtmlRunTranscriptSerializer
from feditest.testruntranscriptserializer.summary import SummaryTestRunTranscriptSerializer
from feditest.testruntranscriptserializer.tap import TapTestRunTranscriptSerializer
from feditest.utils import FEDITEST_VERSION

DEFAULT_TEMPLATE_PATH = "default"

def run(parser: ArgumentParser, args: Namespace, remaining: list[str]) -> int:
"""
Run this command.
Expand All @@ -28,21 +24,21 @@ def run(parser: ArgumentParser, args: Namespace, remaining: list[str]) -> int:
if not transcript.has_compatible_version():
warning(f'Transcript was created by FediTest { transcript.feditest_version }, you are running FediTest { FEDITEST_VERSION }: incompatibilities may occur.')

if isinstance(args.tap, str) or args.tap:
tap_serializer = TapTestRunTranscriptSerializer(transcript)
tap_serializer.write(args.tap)
if isinstance(args.html, str):
HtmlRunTranscriptSerializer(args.template_path).write(transcript, args.html)
elif args.html:
warning('--html requires a filename: skipping')
elif args.template_path:
warning('--template-path only supported with --html. Ignoring.')

if isinstance(args.html, str) or args.html:
multifile_serializer = MultifileRunTranscriptSerializer(args.html, args.template_path)
multifile_serializer.write(transcript)
if isinstance(args.tap, str) or args.tap:
TapTestRunTranscriptSerializer().write(transcript, args.tap)

if isinstance(args.json, str) or args.json:
json_serializer = JsonTestRunTranscriptSerializer(transcript)
json_serializer.write(args.json)
JsonTestRunTranscriptSerializer().write(transcript, args.json)

if isinstance(args.summary, str) or args.summary:
summary_serializer = SummaryTestRunTranscriptSerializer(transcript)
summary_serializer.write(args.json)
SummaryTestRunTranscriptSerializer().write(transcript, args.summary)

return 0

Expand All @@ -60,7 +56,7 @@ def add_sub_parser(parent_parser: _SubParsersAction, cmd_name: str) -> None:
html_group = parser.add_argument_group('html', 'HTML options')
html_group.add_argument('--html',
help="Write results in HTML format to the provided file.")
html_group.add_argument('--template-path', default=DEFAULT_TEMPLATE_PATH,
html_group.add_argument('--template-path', required=False,
help="When specifying --html, use this template path override (comma separated directory names)")
parser.add_argument('--json', nargs="?", const=True, default=False,
help="Write results in JSON format to stdout, or to the provided file (if given).")
Expand Down
1 change: 0 additions & 1 deletion src/feditest/cli/commands/create_session_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
def run(parser: ArgumentParser, args: Namespace, remaining: list[str]) -> int:
"""
Run this command.
> feditest generate-settion-template --testsdir tests --all --out full-partially-automated-template.json
"""
if len(remaining):
parser.print_help()
Expand Down
6 changes: 3 additions & 3 deletions src/feditest/cli/commands/create_testplan.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from argparse import ArgumentParser, Namespace, _SubParsersAction
import feditest
from feditest.cli.utils import create_plan_from_session_templates_and_constellations
from feditest.cli.utils import create_plan_from_session_and_constellations
from feditest.reporting import fatal

def run(parser: ArgumentParser, args: Namespace, remaining: list[str]) -> int:
Expand All @@ -18,7 +18,7 @@ def run(parser: ArgumentParser, args: Namespace, remaining: list[str]) -> int:
feditest.load_default_tests()
feditest.load_tests_from(args.testsdir)

test_plan = create_plan_from_session_templates_and_constellations(args)
test_plan = create_plan_from_session_and_constellations(args)
if test_plan:
if args.out:
test_plan.save(args.out)
Expand All @@ -43,7 +43,7 @@ def add_sub_parser(parent_parser: _SubParsersAction, cmd_name: str) -> None:
# test plan options
parser.add_argument('--name', default=None, required=False, help='Name of the generated test plan')
parser.add_argument('--constellation', action='append', help='File(s) each containing a JSON fragment defining a constellation')
parser.add_argument('--session', '--session-template', action='append', help='File(s) each containing a JSON fragment defining a test session')
parser.add_argument('--session', '--session-template', required=False, help='File containing a JSON fragment defining a test session')
parser.add_argument('--node', action='append',
help="Use role=file to specify that the node definition in 'file' is supposed to be used for constellation role 'role'")
parser.add_argument('--filter-regex', default=None, help='Only include tests whose name matches this regular expression')
Expand Down
45 changes: 20 additions & 25 deletions src/feditest/cli/commands/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,25 @@
"""

from argparse import ArgumentParser, Namespace, _SubParsersAction
from typing import cast

import feditest
from feditest.cli.utils import (
create_plan_from_session_templates_and_constellations,
create_plan_from_session_and_constellations,
create_plan_from_testplan
)
from feditest.registry import Registry, set_registry_singleton
from feditest.reporting import fatal, warning
from feditest.testplan import TestPlan
from feditest.testrun import TestRun
from feditest.testruncontroller import AutomaticTestRunController, InteractiveTestRunController, TestRunController
from feditest.testruntranscript import (
JsonTestRunTranscriptSerializer,
MultifileRunTranscriptSerializer,
SummaryTestRunTranscriptSerializer,
TapTestRunTranscriptSerializer,
TestRunTranscriptSerializer,
)
from feditest.testruntranscriptserializer.json import JsonTestRunTranscriptSerializer
from feditest.testruntranscriptserializer.html import HtmlRunTranscriptSerializer
from feditest.testruntranscriptserializer.summary import SummaryTestRunTranscriptSerializer
from feditest.testruntranscriptserializer.tap import TapTestRunTranscriptSerializer
from feditest.utils import FEDITEST_VERSION, hostname_validate


DEFAULT_TEMPLATE = 'default'

def run(parser: ArgumentParser, args: Namespace, remaining: list[str]) -> int:
"""
Run this command.
Expand All @@ -49,7 +45,7 @@ def run(parser: ArgumentParser, args: Namespace, remaining: list[str]) -> int:
if args.testplan:
plan = create_plan_from_testplan(args)
else:
plan = create_plan_from_session_templates_and_constellations(args)
plan = create_plan_from_session_and_constellations(args)

if not plan:
fatal('Cannot find or create test plan ')
Expand All @@ -71,22 +67,21 @@ def run(parser: ArgumentParser, args: Namespace, remaining: list[str]) -> int:

transcript : feditest.testruntranscript.TestRunTranscript = test_run.transcribe()

summary_serializer = SummaryTestRunTranscriptSerializer(transcript)
serializer : TestRunTranscriptSerializer | None = None
if isinstance(args.tap, str) or args.tap:
serializer = TapTestRunTranscriptSerializer(transcript)
serializer.write(args.tap)
TapTestRunTranscriptSerializer().write(transcript, cast(str|None, args.tap))

if isinstance(args.html, str) or args.html:
multifile_serializer = MultifileRunTranscriptSerializer(args.html, args.template)
multifile_serializer.write(transcript)
if isinstance(args.html, str):
HtmlRunTranscriptSerializer(args.template_path).write(transcript, args.html)
elif args.html:
warning('--html requires a filename: skipping')
elif args.template_path:
warning('--template-path only supported with --html. Ignoring.')

if isinstance(args.json, str) or args.json:
serializer = JsonTestRunTranscriptSerializer(transcript)
serializer.write(args.json)
JsonTestRunTranscriptSerializer().write(transcript, args.json)

if isinstance(args.summary, str) or args.summary or serializer is None:
summary_serializer.write(args.summary)
if isinstance(args.summary, str) or args.summary:
SummaryTestRunTranscriptSerializer().write(transcript, args.summary)

if transcript.build_summary().n_failed > 0:
print('FAILED.')
Expand All @@ -112,7 +107,7 @@ def add_sub_parser(parent_parser: _SubParsersAction, cmd_name: str) -> None:
parser.add_argument('--name', default=None, required=False, help='Name of the generated test plan')
parser.add_argument('--testplan', help='Name of the file that contains the test plan to run')
parser.add_argument('--constellation', action='append', help='File(s) each containing a JSON fragment defining a constellation')
parser.add_argument('--session', '--session-template', action='append', help='File(s) each containing a JSON fragment defining a test session')
parser.add_argument('--session', '--session-template', required=False, help='File(s) each containing a JSON fragment defining a test session')
parser.add_argument('--node', action='append',
help="Use role=file to specify that the node definition in 'file' is supposed to be used for constellation role 'role'")
parser.add_argument('--filter-regex', default=None, help='Only include tests whose name matches this regular expression')
Expand All @@ -124,8 +119,8 @@ def add_sub_parser(parent_parser: _SubParsersAction, cmd_name: str) -> None:
html_group = parser.add_argument_group('html', 'HTML options')
html_group.add_argument('--html',
help="Write results in HTML format to the provided file.")
html_group.add_argument('--template', default=DEFAULT_TEMPLATE,
help=f"When specifying --html, use this template (defaults to '{ DEFAULT_TEMPLATE }').")
html_group.add_argument('--template-path', required=False,
help="When specifying --html, use this template path override (comma separated directory names)")
parser.add_argument('--json', '--testresult', nargs="?", const=True, default=False,
help="Write results in JSON format to stdout, or to the provided file (if given).")
parser.add_argument('--summary', nargs="?", const=True, default=False,
Expand Down
49 changes: 13 additions & 36 deletions src/feditest/cli/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,18 @@

from argparse import ArgumentError, Namespace
import re
from typing import Any

from msgspec import ValidationError

import feditest
from feditest.tests import Test
from feditest.testplan import TestPlan, TestPlanConstellation, TestPlanConstellationNode, TestPlanSession, TestPlanTestSpec
from feditest.testplan import TestPlan, TestPlanConstellation, TestPlanConstellationNode, TestPlanSessionTemplate, TestPlanTestSpec

def create_plan_from_testplan(args: Namespace) -> TestPlan:
if args.constellation:
raise ArgumentError(None, '--testplan already defines --constellation. Do not provide both.')
if args.session:
raise ArgumentError(None, '--testplan already defines --session-template. Do not provide both.')
raise ArgumentError(None, '--testplan already defines --session. Do not provide both.')
if args.node:
raise ArgumentError(None, '--testplan already defines --node via the contained constellation. Do not provide both.')
if args.test:
Expand All @@ -25,46 +24,33 @@ def create_plan_from_testplan(args: Namespace) -> TestPlan:
return plan


def create_plan_from_session_templates_and_constellations(args: Namespace) -> TestPlan | None:
session_templates = create_session_templates(args)
def create_plan_from_session_and_constellations(args: Namespace) -> TestPlan | None:
session = create_session(args)
constellations = create_constellations(args)

plan : TestPlan | None = None
sessions = []
for session_template in session_templates:
for constellation in constellations:
session = session_template.instantiate_with_constellation(constellation, constellation.name)
sessions.append(session)
if sessions:
plan = TestPlan(sessions, args.name)
plan.simplify()
plan = TestPlan(session, constellations, args.name)
plan.simplify()
return plan


def create_session_templates(args: Namespace) -> list[TestPlanSession]:
def create_session(args: Namespace) -> TestPlanSessionTemplate:
if args.session:
session_templates = create_session_templates_from_files(args)
session_template = create_session_from_files(args)
else:
session_template = create_session_template_from_tests(args)
session_templates = [ session_template ]
return session_templates
return session_template


def create_session_templates_from_files(args: Namespace) -> list[TestPlanSession]:
def create_session_from_files(args: Namespace) -> TestPlanSessionTemplate:
if args.filter_regex:
raise ArgumentError(None, '--session already defines the tests, do not provide --filter-regex')
if args.test:
raise ArgumentError(None, '--session already defines --test. Do not provide both.')
session_templates = []
for session_file in args.session:
session_templates.append(TestPlanSession.load(session_file))
return session_templates
return TestPlanSessionTemplate.load(args.session)


def create_session_template_from_tests(args: Namespace) -> TestPlanSession:
def create_session_template_from_tests(args: Namespace) -> TestPlanSessionTemplate:
test_plan_specs : list[TestPlanTestSpec]= []
constellation_role_names : dict[str,Any] = {}
constellation_roles: dict[str,TestPlanConstellationNode | None] = {}
tests : list[Test]= []

if args.test:
Expand Down Expand Up @@ -101,16 +87,7 @@ def create_session_template_from_tests(args: Namespace) -> TestPlanSession:
test_plan_spec = TestPlanTestSpec(name)
test_plan_specs.append(test_plan_spec)

for role_name in test.needed_local_role_names():
constellation_role_names[role_name] = 1
if not test_plan_spec.rolemapping:
test_plan_spec.rolemapping = {}
test_plan_spec.rolemapping[role_name] = role_name

for constellation_role_name in constellation_role_names:
constellation_roles[constellation_role_name] = None

session = TestPlanSession(TestPlanConstellation(constellation_roles), test_plan_specs, args.name)
session = TestPlanSessionTemplate(test_plan_specs, args.name)
return session


Expand Down
4 changes: 0 additions & 4 deletions src/feditest/templates/default/partials/shared/footer.jinja2

This file was deleted.

6 changes: 0 additions & 6 deletions src/feditest/templates/default/partials/shared/mobile.jinja2

This file was deleted.

Loading
Loading