diff --git a/launchable/test_runners/perl.py b/launchable/test_runners/perl.py new file mode 100644 index 000000000..3baef68c0 --- /dev/null +++ b/launchable/test_runners/perl.py @@ -0,0 +1,56 @@ +import click +from junitparser import TestCase, TestSuite # type: ignore + +from ..testpath import TestPath +from . import launchable + + +@launchable.subset +def subset(client): + # read lines as test file names + for t in client.stdin(): + client.test_path(t.rstrip("\n")) + + client.run() + + +@click.argument('reports', required=True, nargs=-1) +@launchable.record.tests +def record_tests(client, reports): + + def path_builder(case: TestCase, suite: TestSuite, + report_file: str) -> TestPath: + def find_filename(): + # find file path from test suite attribute first. + filepath = suite._elem.attrib.get("name") + if filepath: + return filepath + # find file path from test case attribute. + filepath = case._elem.attrib.get("classname") + if filepath: + return filepath + return None # failing to find a test name + + filepath = find_filename() + if not filepath: + raise click.ClickException( + "No file name found in %s." + "Perl profile is made to take Junit report produced by " + "TAP::Harness::JUnit (https://metacpan.org/pod/TAP::Harness::JUnit) " + "with environment variable of JUNIT_NAME_MANGLE=none. " + "If you are not using TAP::Harness::JUnit, " + "please change your reporting to TAP::Harness::JUnit." % report_file) + + # default test path in `subset` expects to have this file name + test_path = [client.make_file_path_component(filepath)] + if case.name: + test_path.append({"type": "testcase", "name": case.name}) + return test_path + client.path_builder = path_builder + + for r in reports: + client.report(r) + client.run() + + +split_subset = launchable.CommonSplitSubsetImpls(__name__).split_subset() diff --git a/tests/data/perl/record_test_result.json b/tests/data/perl/record_test_result.json new file mode 100644 index 000000000..a85f55547 --- /dev/null +++ b/tests/data/perl/record_test_result.json @@ -0,0 +1,133 @@ +{ + "events": [ + { + "type": "case", + "testPath": [ + { + "type": "file", + "name": "t/easy/01_easy.t" + }, + { + "type": "testcase", + "name": "a + b = ab" + } + ], + "duration": 0.153996229171753, + "status": 1, + "stdout": "", + "stderr": "", + "data": null + }, + { + "type": "case", + "testPath": [ + { + "type": "file", + "name": "t/easy/01_easy.t" + }, + { + "type": "testcase", + "name": "str_concat {" + } + ], + "duration": 0.00043487548828125, + "status": 1, + "stdout": "", + "stderr": "", + "data": null + }, + { + "type": "case", + "testPath": [ + { + "type": "file", + "name": "t/math/01_math.t" + }, + { + "type": "testcase", + "name": "add(1, 2) == 3" + } + ], + "duration": 0.0723011493682861, + "status": 1, + "stdout": "", + "stderr": "", + "data": null + }, + { + "type": "case", + "testPath": [ + { + "type": "file", + "name": "t/math/01_math.t" + }, + { + "type": "testcase", + "name": "add" + } + ], + "duration": 0.000227928161621094, + "status": 1, + "stdout": "", + "stderr": "", + "data": null + }, + { + "type": "case", + "testPath": [ + { + "type": "file", + "name": "t/math/01_math.t" + }, + { + "type": "testcase", + "name": "double" + } + ], + "duration": 7.91549682617188e-05, + "status": 1, + "stdout": "", + "stderr": "", + "data": null + }, + { + "type": "case", + "testPath": [ + { + "type": "file", + "name": "t/math/01_math.t" + }, + { + "type": "testcase", + "name": "double_fail" + } + ], + "duration": 0.000271081924438477, + "status": 0, + "stdout": "", + "stderr": "", + "data": null + }, + { + "type": "case", + "testPath": [ + { + "type": "file", + "name": "t/00_compile.t" + }, + { + "type": "testcase", + "name": "use Example;" + } + ], + "duration": 0.0674030780792236, + "status": 1, + "stdout": "", + "stderr": "", + "data": null + } + ], + "testRunner": "perl", + "group": "", + "noBuild": false +} diff --git a/tests/data/perl/report.xml b/tests/data/perl/report.xml new file mode 100644 index 000000000..32b3d1838 --- /dev/null +++ b/tests/data/perl/report.xml @@ -0,0 +1,51 @@ + + + + ok 1 - a + b = ab +ok 2 - str_concat { + ok 1 - a + dddd + ok 2 - bb + ccc + 1..2 +} +1..2 + + + + + + ok 1 - add(1, 2) == 3 +# Subtest: add + ok 1 - 1 + 2 + ok 2 - 3 + 4 + 1..2 +ok 2 - add +# Subtest: double + ok 1 - 1 + 2 + ok 2 - 3 + 2 + 1..2 +ok 3 - double +# Subtest: double_fail + not ok 1 - fail 1 + 2 + not ok 2 - fail 3 + 2 + 1..2 +not ok 4 - double_fail +1..4 + + + + + + Subtest: double_fail + not ok 1 - fail 1 + 2 + not ok 2 - fail 3 + 2 + 1..2 + + + + + ok 1 - use Example; +1..1 + + + + diff --git a/tests/test_runners/test_perl.py b/tests/test_runners/test_perl.py new file mode 100644 index 000000000..dd8b2d84e --- /dev/null +++ b/tests/test_runners/test_perl.py @@ -0,0 +1,35 @@ +import gzip +import json +import os +from pathlib import Path +from unittest import mock + +import responses # type: ignore + +from launchable.utils.session import read_session, write_build +from tests.cli_test_case import CliTestCase + + +class PerlTestTest(CliTestCase): + test_files_dir = Path(__file__).parent.joinpath('../data/perl/').resolve() + + @responses.activate + @mock.patch.dict(os.environ, {"LAUNCHABLE_TOKEN": CliTestCase.launchable_token}) + def test_record_tests(self): + # emulate launchable record build + write_build(self.build_name) + + result = self.cli('record', 'tests', 'perl', str(self.test_files_dir.joinpath('report.xml'))) + self.assertEqual(result.exit_code, 0) + + self.assertEqual(read_session(self.build_name), self.session) + + self.assertIn('events', responses.calls[2].request.url, 'call events API') + payload = json.loads(gzip.decompress(responses.calls[2].request.body).decode()) + for c in payload['events']: + del c['created_at'] + + expected = self.load_json_from_file(self.test_files_dir.joinpath('record_test_result.json')) + self.assert_json_orderless_equal(expected, payload) + + self.assertIn('close', responses.calls[4].request.url, 'call close API')