Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F738966
MavenTestEngine.php
sgrimm (Steven Grimm)
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Authored By
sgrimm
Aug 20 2015, 2:14 PM
2015-08-20 14:14:52 (UTC+0)
Size
5 KB
Referenced Files
None
Subscribers
None
MavenTestEngine.php
View Options
<?php
/**
* Basic test engine for running tests using Maven.
*/
final
class
MavenTestEngine
extends
ArcanistUnitTestEngine
{
private
$project_root
;
public
function
run
()
{
$working_copy
=
$this
->
getWorkingCopy
();
$this
->
project_root
=
$working_copy
->
getProjectRoot
();
// We only want to report results for tests that actually ran, so
// we'll compare the test result files' timestamps to the start time
// of the test run. This will probably break if multiple test runs
// are happening in parallel, but if that's happening then we can't
// count on the results files being intact anyway.
$start_time
=
time
();
$maven_top_dirs
=
$this
->
findTopLevelMavenDirectories
();
// We'll figure out if any of the modified files we're testing are in
// Maven directories. We won't want to run a bunch of Java tests for
// changes to CSS files or whatever.
$modified_paths
=
$this
->
getModifiedPaths
();
$maven_failed
=
false
;
foreach
(
$maven_top_dirs
as
$dir
)
{
$dir_with_trailing_slash
=
$dir
.
'/'
;
foreach
(
$modified_paths
as
$path
)
{
if
(
$dir_with_trailing_slash
===
substr
(
$path
,
0
,
strlen
(
$dir_with_trailing_slash
)))
{
$future
=
new
ExecFuture
(
'mvn test'
);
$future
->
setCWD
(
$dir
);
list
(
$status
,
$stdout
,
$stderr
)
=
$future
->
resolve
();
if
(
$status
)
{
// Maven exits with a nonzero status if there were test failures
// or if there was a compilation error.
$maven_failed
=
true
;
break
2
;
}
break
;
}
}
}
$testResults
=
$this
->
parseTestResultsSince
(
$start_time
);
if
(
$maven_failed
)
{
// If there wasn't a test failure, then synthesize one to represent
// the failure of the test run as a whole, since it probably means the
// code failed to compile.
$found_failure
=
false
;
foreach
(
$testResults
as
$testResult
)
{
if
(
$testResult
->
getResult
()
===
ArcanistUnitTestResult
::
RESULT_FAIL
||
$testResult
->
getResult
()
===
ArcanistUnitTestResult
::
RESULT_BROKEN
)
{
$found_failure
=
true
;
break
;
}
}
if
(!
$found_failure
)
{
$testResult
=
new
ArcanistUnitTestResult
();
$testResult
->
setResult
(
ArcanistUnitTestResult
::
RESULT_BROKEN
);
$testResult
->
setName
(
'mvn test'
);
$testResults
[]
=
$testResult
;
}
}
return
$testResults
;
}
/**
* Returns an array of the full canonical paths to all the Maven directories
* (directories containing pom.xml files) in the project.
*/
private
function
findMavenDirectories
()
{
if
(
file_exists
(
$this
->
project_root
.
"/.git"
))
{
// The fastest way to find all the pom.xml files is to let git scan
// its index.
$future
=
new
ExecFuture
(
'git ls-files
\*
/pom.xml'
);
}
else
{
// Not a git repo. Do it the old-fashioned way.
$future
=
new
ExecFuture
(
'find . -name pom.xml -print'
);
}
// TODO: This will find *all* the pom.xml files in the working copy.
// Need to obey the optional paths argument to "arc unit" to let users
// run just a subset of tests.
$future
->
setCWD
(
$this
->
project_root
);
list
(
$stdout
)
=
$future
->
resolvex
();
$poms
=
explode
(
"
\n
"
,
trim
(
$stdout
));
if
(!
$poms
)
{
throw
new
Exception
(
"No pom.xml files found"
);
}
$maven_dirs
=
array_map
(
function
(
$pom
)
{
$maven_dir
=
dirname
(
$pom
);
return
realpath
(
$this
->
project_root
.
'/'
.
$maven_dir
);
},
$poms
);
return
$maven_dirs
;
}
/**
* Returns an array of the full canonical paths to all the top-level Maven
* directories in the project. A directory is not considered top-level if
* one of its parent directories has a pom.xml.
*/
private
function
findTopLevelMavenDirectories
()
{
$maven_dirs
=
$this
->
findMavenDirectories
();
sort
(
$maven_dirs
);
$previous_top_dir
=
'-'
;
$top_dirs
=
array
();
foreach
(
$maven_dirs
as
$maven_dir
)
{
if
(
$previous_top_dir
!==
substr
(
$maven_dir
.
'/'
,
0
,
strlen
(
$previous_top_dir
)))
{
$previous_top_dir
=
$maven_dir
.
'/'
;
$top_dirs
[]
=
$maven_dir
;
}
}
return
$top_dirs
;
}
/**
* Returns an array of paths to the JUnit test result XML files in the
* project.
*/
private
function
findTestResultFiles
()
{
$maven_dirs
=
$this
->
findMavenDirectories
();
$result_dirs
=
array
();
foreach
(
$maven_dirs
as
$maven_dir
)
{
$fullpath
=
$maven_dir
.
'/target/surefire-reports'
;
if
(
file_exists
(
$fullpath
))
{
$result_dirs
[]
=
$fullpath
;
}
}
$result_files
=
array
();
foreach
(
$result_dirs
as
$result_dir
)
{
$xmlfiles
=
glob
(
$result_dir
.
"/*.xml"
);
$result_files
=
array_merge
(
$result_files
,
$xmlfiles
);
}
return
$result_files
;
}
/**
* Returns the full paths to all the files modified in the workspace.
*/
private
function
getModifiedPaths
()
{
$paths
=
$this
->
getPaths
();
return
array_map
(
function
(
$path
)
{
return
realpath
(
$this
->
project_root
.
'/'
.
$path
);
},
$paths
);
}
/**
* Parses all the test results that have been written since a particular
* starting time.
*/
private
function
parseTestResultsSince
(
$start_time
)
{
$parser
=
new
ArcanistXUnitTestResultParser
();
$results
=
array
();
$result_files
=
$this
->
findTestResultFiles
();
foreach
(
$result_files
as
$file
)
{
$stat
=
stat
(
$file
);
if
(
$stat
&&
$stat
[
'mtime'
]
>=
$start_time
)
{
$new_results
=
$parser
->
parseTestResults
(
Filesystem
::
readFile
(
$file
));
if
(
$new_results
)
{
$results
=
array_merge
(
$results
,
$new_results
);
}
}
}
return
$results
;
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Storage Engine
amazon-s3
Storage Format
Raw Data
Storage Handle
phabricator/yg/e6/vx327ortkq2bcx76
Default Alt Text
MavenTestEngine.php (5 KB)
Attached To
Mode
T9223: Allow `arc diff` to run a build step like `gradle` first, then read lint and unit messages from the output
Attached
Detach File
Event Timeline
Log In to Comment