-
-
Notifications
You must be signed in to change notification settings - Fork 648
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add proof-of-concept Java junit test rule. (#12177)
This implementation is just good enough to demonstrate how to use the existing Pants Java infrastructure to compile and consume Java source for the purpose of executing junit tests. This initial iteration has several limitations: * jUnit5 (org.junit.platform:junit-platform-console:1.7.2) is hard-coded as the JUnit runner in the rule source. As needed, this can be hoisted into a subsystem for configurability. By design, junit4 is not supported as a **runner**, because its classpath scanning isn't powerful enough. However, junit4 tests can still be run with the junit5 runner. * junit_tests targets have the same requirement of java_library targets that there must be exactly 1 coursier_lockfile dependency in the transitive closure of the junit_tests target. In practice this means that any third party dependencies required by the test source must also be shared by the library targets upon which the test transitively depends. Lockfile subsetting will mostly make this a non-issue, but it's still unfortunate that all test targets are indirectly locked to all other test targets that transitively depend on the same Java library code. * Due to #12293, the test runner currently hard-codes the Coursier `--system-jvm` argument. Future revisions will expose this as an option via `junit_test` parameters and/or a junit subsystem. [ci skip-rust] [ci skip-build-wheels]
- Loading branch information
1 parent
8c319ae
commit 1552119
Showing
4 changed files
with
737 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# Copyright 2021 Pants project contributors (see CONTRIBUTORS.md). | ||
# Licensed under the Apache License, Version 2.0 (see LICENSE). | ||
|
||
python_library() | ||
python_tests(name="tests", timeout=240) |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
# Copyright 2021 Pants project contributors (see CONTRIBUTORS.md). | ||
# Licensed under the Apache License, Version 2.0 (see LICENSE). | ||
|
||
import logging | ||
from dataclasses import dataclass | ||
|
||
from pants.backend.java.compile.javac import CompiledClassfiles, CompileJavaSourceRequest | ||
from pants.backend.java.target_types import JavaTestsSources | ||
from pants.core.goals.test import TestFieldSet, TestResult | ||
from pants.engine.addresses import Addresses | ||
from pants.engine.fs import AddPrefix, Digest, MergeDigests | ||
from pants.engine.process import FallibleProcessResult, Process | ||
from pants.engine.rules import Get, MultiGet, collect_rules, rule | ||
from pants.engine.target import ( | ||
CoarsenedTargets, | ||
Targets, | ||
TransitiveTargets, | ||
TransitiveTargetsRequest, | ||
) | ||
from pants.engine.unions import UnionRule | ||
from pants.jvm.resolve.coursier_fetch import ( | ||
CoursierLockfileForTargetRequest, | ||
CoursierResolvedLockfile, | ||
MaterializedClasspath, | ||
MaterializedClasspathRequest, | ||
MavenRequirements, | ||
) | ||
from pants.jvm.resolve.coursier_setup import Coursier | ||
from pants.util.logging import LogLevel | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
@dataclass(frozen=True) | ||
class JavaTestFieldSet(TestFieldSet): | ||
required_fields = (JavaTestsSources,) | ||
|
||
sources: JavaTestsSources | ||
|
||
|
||
@rule(desc="Run JUnit", level=LogLevel.DEBUG) | ||
async def run_junit_test( | ||
coursier: Coursier, | ||
field_set: JavaTestFieldSet, | ||
) -> TestResult: | ||
transitive_targets = await Get(TransitiveTargets, TransitiveTargetsRequest([field_set.address])) | ||
coarsened_targets = await Get( | ||
CoarsenedTargets, Addresses(t.address for t in transitive_targets.closure) | ||
) | ||
lockfile = await Get( | ||
CoursierResolvedLockfile, | ||
CoursierLockfileForTargetRequest(Targets(transitive_targets.closure)), | ||
) | ||
materialized_classpath = await Get( | ||
MaterializedClasspath, | ||
MaterializedClasspathRequest( | ||
prefix="__thirdpartycp", | ||
lockfiles=(lockfile,), | ||
maven_requirements=( | ||
MavenRequirements.create_from_maven_coordinates_fields( | ||
fields=(), | ||
additional_requirements=[ | ||
"org.junit.platform:junit-platform-console:1.7.2", | ||
"org.junit.jupiter:junit-jupiter-engine:5.7.2", | ||
"org.junit.vintage:junit-vintage-engine:5.7.2", | ||
], | ||
), | ||
), | ||
), | ||
) | ||
transitive_user_classfiles = await MultiGet( | ||
Get(CompiledClassfiles, CompileJavaSourceRequest(component=t)) for t in coarsened_targets | ||
) | ||
merged_transitive_user_classfiles_digest = await Get( | ||
Digest, MergeDigests(classfiles.digest for classfiles in transitive_user_classfiles) | ||
) | ||
usercp_relpath = "__usercp" | ||
prefixed_transitive_user_classfiles_digest = await Get( | ||
Digest, AddPrefix(merged_transitive_user_classfiles_digest, usercp_relpath) | ||
) | ||
merged_digest = await Get( | ||
Digest, | ||
MergeDigests( | ||
( | ||
prefixed_transitive_user_classfiles_digest, | ||
materialized_classpath.digest, | ||
coursier.digest, | ||
) | ||
), | ||
) | ||
proc = Process( | ||
argv=[ | ||
coursier.coursier.exe, | ||
"java", | ||
"--system-jvm", # TODO(#12293): use a fixed JDK version from a subsystem. | ||
"-cp", | ||
materialized_classpath.classpath_arg(), | ||
"org.junit.platform.console.ConsoleLauncher", | ||
"--classpath", | ||
usercp_relpath, | ||
"--scan-class-path", | ||
usercp_relpath, | ||
], | ||
input_digest=merged_digest, | ||
description=f"Run JUnit 5 ConsoleLauncher against {field_set.address}", | ||
level=LogLevel.DEBUG, | ||
) | ||
|
||
process_result = await Get( | ||
FallibleProcessResult, | ||
Process, | ||
proc, | ||
) | ||
|
||
return TestResult.from_fallible_process_result( | ||
process_result, | ||
address=field_set.address, | ||
) | ||
|
||
|
||
def rules(): | ||
return [ | ||
*collect_rules(), | ||
UnionRule(TestFieldSet, JavaTestFieldSet), | ||
] |
Oops, something went wrong.