Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in / Register
Toggle navigation
S
spring-boot
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
DEMO
spring-boot
Commits
11b77037
Commit
11b77037
authored
Feb 24, 2021
by
Andy Wilkinson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Make TestFailuresPlugin compatible with Gradle's configuration cache
Closes gh-25405
parent
a1a61a44
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
109 additions
and
77 deletions
+109
-77
TestFailuresPlugin.java
...pringframework/boot/build/testing/TestFailuresPlugin.java
+12
-75
TestResultsOverview.java
...ringframework/boot/build/testing/TestResultsOverview.java
+95
-0
TestFailuresPluginIntegrationTests.java
...oot/build/testing/TestFailuresPluginIntegrationTests.java
+2
-2
No files found.
buildSrc/src/main/java/org/springframework/boot/build/testing/TestFailuresPlugin.java
View file @
11b77037
/*
/*
* Copyright 2012-202
0
the original author or authors.
* Copyright 2012-202
1
the original author or authors.
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* you may not use this file except in compliance with the License.
...
@@ -17,14 +17,11 @@
...
@@ -17,14 +17,11 @@
package
org
.
springframework
.
boot
.
build
.
testing
;
package
org
.
springframework
.
boot
.
build
.
testing
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.TreeMap
;
import
org.gradle.BuildResult
;
import
org.gradle.api.Plugin
;
import
org.gradle.api.Plugin
;
import
org.gradle.api.Project
;
import
org.gradle.api.Project
;
import
org.gradle.api.provider.Provider
;
import
org.gradle.api.tasks.testing.Test
;
import
org.gradle.api.tasks.testing.Test
;
import
org.gradle.api.tasks.testing.TestDescriptor
;
import
org.gradle.api.tasks.testing.TestDescriptor
;
import
org.gradle.api.tasks.testing.TestListener
;
import
org.gradle.api.tasks.testing.TestListener
;
...
@@ -39,46 +36,37 @@ public class TestFailuresPlugin implements Plugin<Project> {
...
@@ -39,46 +36,37 @@ public class TestFailuresPlugin implements Plugin<Project> {
@Override
@Override
public
void
apply
(
Project
project
)
{
public
void
apply
(
Project
project
)
{
TestResultsExtension
testResults
=
getOrCreateTestResults
(
project
);
Provider
<
TestResultsOverview
>
testResultsOverview
=
project
.
getGradle
().
getSharedServices
()
.
registerIfAbsent
(
"testResultsOverview"
,
TestResultsOverview
.
class
,
(
spec
)
->
{
});
project
.
getTasks
().
withType
(
Test
.
class
,
project
.
getTasks
().
withType
(
Test
.
class
,
(
test
)
->
test
.
addTestListener
(
new
FailureRecordingTestListener
(
testResults
,
test
)));
(
test
)
->
test
.
addTestListener
(
new
FailureRecordingTestListener
(
testResultsOverview
,
test
)));
}
private
TestResultsExtension
getOrCreateTestResults
(
Project
project
)
{
TestResultsExtension
testResults
=
project
.
getRootProject
().
getExtensions
()
.
findByType
(
TestResultsExtension
.
class
);
if
(
testResults
==
null
)
{
testResults
=
project
.
getRootProject
().
getExtensions
().
create
(
"testResults"
,
TestResultsExtension
.
class
);
project
.
getRootProject
().
getGradle
().
buildFinished
(
testResults:
:
buildFinished
);
}
return
testResults
;
}
}
private
final
class
FailureRecordingTestListener
implements
TestListener
{
private
final
class
FailureRecordingTestListener
implements
TestListener
{
private
final
List
<
Test
Failure
>
failures
=
new
ArrayList
<>();
private
final
List
<
Test
Descriptor
>
failures
=
new
ArrayList
<>();
private
final
TestResultsExtension
testResults
;
private
final
Provider
<
TestResultsOverview
>
testResultsOverview
;
private
final
Test
test
;
private
final
Test
test
;
private
FailureRecordingTestListener
(
TestResultsExtension
testResults
,
Test
test
)
{
private
FailureRecordingTestListener
(
Provider
<
TestResultsOverview
>
testResultOverview
,
Test
test
)
{
this
.
testResults
=
testResults
;
this
.
testResults
Overview
=
testResultOverview
;
this
.
test
=
test
;
this
.
test
=
test
;
}
}
@Override
@Override
public
void
afterSuite
(
TestDescriptor
descriptor
,
TestResult
result
)
{
public
void
afterSuite
(
TestDescriptor
descriptor
,
TestResult
result
)
{
if
(!
this
.
failures
.
isEmpty
())
{
if
(!
this
.
failures
.
isEmpty
())
{
Collections
.
sort
(
this
.
failures
);
this
.
testResultsOverview
.
get
().
addFailures
(
this
.
test
,
this
.
failures
);
this
.
testResults
.
addFailures
(
this
.
test
,
this
.
failures
);
}
}
}
}
@Override
@Override
public
void
afterTest
(
TestDescriptor
descriptor
,
TestResult
result
)
{
public
void
afterTest
(
TestDescriptor
descriptor
,
TestResult
result
)
{
if
(
result
.
getFailedTestCount
()
>
0
)
{
if
(
result
.
getFailedTestCount
()
>
0
)
{
this
.
failures
.
add
(
new
TestFailure
(
descriptor
)
);
this
.
failures
.
add
(
descriptor
);
}
}
}
}
...
@@ -94,55 +82,4 @@ public class TestFailuresPlugin implements Plugin<Project> {
...
@@ -94,55 +82,4 @@ public class TestFailuresPlugin implements Plugin<Project> {
}
}
private
static
final
class
TestFailure
implements
Comparable
<
TestFailure
>
{
private
final
TestDescriptor
descriptor
;
private
TestFailure
(
TestDescriptor
descriptor
)
{
this
.
descriptor
=
descriptor
;
}
@Override
public
int
compareTo
(
TestFailure
other
)
{
int
comparison
=
this
.
descriptor
.
getClassName
().
compareTo
(
other
.
descriptor
.
getClassName
());
if
(
comparison
==
0
)
{
comparison
=
this
.
descriptor
.
getName
().
compareTo
(
other
.
descriptor
.
getName
());
}
return
comparison
;
}
}
public
static
class
TestResultsExtension
{
private
final
Map
<
Test
,
List
<
TestFailure
>>
testFailures
=
new
TreeMap
<>(
(
one
,
two
)
->
one
.
getPath
().
compareTo
(
two
.
getPath
()));
private
final
Object
monitor
=
new
Object
();
void
addFailures
(
Test
test
,
List
<
TestFailure
>
testFailures
)
{
synchronized
(
this
.
monitor
)
{
this
.
testFailures
.
put
(
test
,
testFailures
);
}
}
public
void
buildFinished
(
BuildResult
result
)
{
synchronized
(
this
.
monitor
)
{
if
(
this
.
testFailures
.
isEmpty
())
{
return
;
}
System
.
err
.
println
();
System
.
err
.
println
(
"Found test failures in "
+
this
.
testFailures
.
size
()
+
" test task"
+
((
this
.
testFailures
.
size
()
==
1
)
?
":"
:
"s:"
));
this
.
testFailures
.
forEach
((
task
,
failures
)
->
{
System
.
err
.
println
();
System
.
err
.
println
(
task
.
getPath
());
failures
.
forEach
((
failure
)
->
System
.
err
.
println
(
" "
+
failure
.
descriptor
.
getClassName
()
+
" > "
+
failure
.
descriptor
.
getName
()));
});
}
}
}
}
}
buildSrc/src/main/java/org/springframework/boot/build/testing/TestResultsOverview.java
0 → 100644
View file @
11b77037
/*
* Copyright 2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
springframework
.
boot
.
build
.
testing
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.TreeMap
;
import
java.util.stream.Collectors
;
import
org.gradle.api.services.BuildService
;
import
org.gradle.api.services.BuildServiceParameters
;
import
org.gradle.api.tasks.testing.Test
;
import
org.gradle.api.tasks.testing.TestDescriptor
;
import
org.gradle.tooling.events.FinishEvent
;
import
org.gradle.tooling.events.OperationCompletionListener
;
/**
* {@link BuildService} that provides an overview of all of the test failures in the
* build.
*
* @author Andy Wilkinson
*/
public
abstract
class
TestResultsOverview
implements
BuildService
<
BuildServiceParameters
.
None
>,
OperationCompletionListener
,
AutoCloseable
{
private
final
Map
<
Test
,
List
<
TestFailure
>>
testFailures
=
new
TreeMap
<>(
(
one
,
two
)
->
one
.
getPath
().
compareTo
(
two
.
getPath
()));
private
final
Object
monitor
=
new
Object
();
void
addFailures
(
Test
test
,
List
<
TestDescriptor
>
failureDescriptors
)
{
List
<
TestFailure
>
testFailures
=
failureDescriptors
.
stream
().
map
(
TestFailure:
:
new
).
sorted
()
.
collect
(
Collectors
.
toList
());
synchronized
(
this
.
monitor
)
{
this
.
testFailures
.
put
(
test
,
testFailures
);
}
}
@Override
public
void
onFinish
(
FinishEvent
event
)
{
// OperationCompletionListener is implemented to defer close until the build ends
}
@Override
public
void
close
()
{
synchronized
(
this
.
monitor
)
{
if
(
this
.
testFailures
.
isEmpty
())
{
return
;
}
System
.
err
.
println
();
System
.
err
.
println
(
"Found test failures in "
+
this
.
testFailures
.
size
()
+
" test task"
+
((
this
.
testFailures
.
size
()
==
1
)
?
":"
:
"s:"
));
this
.
testFailures
.
forEach
((
task
,
failures
)
->
{
System
.
err
.
println
();
System
.
err
.
println
(
task
.
getPath
());
failures
.
forEach
((
failure
)
->
System
.
err
.
println
(
" "
+
failure
.
descriptor
.
getClassName
()
+
" > "
+
failure
.
descriptor
.
getName
()));
});
}
}
private
static
final
class
TestFailure
implements
Comparable
<
TestFailure
>
{
private
final
TestDescriptor
descriptor
;
private
TestFailure
(
TestDescriptor
descriptor
)
{
this
.
descriptor
=
descriptor
;
}
@Override
public
int
compareTo
(
TestFailure
other
)
{
int
comparison
=
this
.
descriptor
.
getClassName
().
compareTo
(
other
.
descriptor
.
getClassName
());
if
(
comparison
==
0
)
{
comparison
=
this
.
descriptor
.
getName
().
compareTo
(
other
.
descriptor
.
getName
());
}
return
comparison
;
}
}
}
buildSrc/src/test/java/org/springframework/boot/build/testing/TestFailuresPluginIntegrationTests.java
View file @
11b77037
/*
/*
* Copyright 2012-202
0
the original author or authors.
* Copyright 2012-202
1
the original author or authors.
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* you may not use this file except in compliance with the License.
...
@@ -84,7 +84,7 @@ class TestFailuresPluginIntegrationTests {
...
@@ -84,7 +84,7 @@ class TestFailuresPluginIntegrationTests {
void
multiProjectParallel
()
throws
IOException
{
void
multiProjectParallel
()
throws
IOException
{
createMultiProjectBuild
();
createMultiProjectBuild
();
BuildResult
result
=
GradleRunner
.
create
().
withDebug
(
true
).
withProjectDir
(
this
.
projectDir
)
BuildResult
result
=
GradleRunner
.
create
().
withDebug
(
true
).
withProjectDir
(
this
.
projectDir
)
.
withArguments
(
"build"
,
"--parallel"
).
withPluginClasspath
().
buildAndFail
();
.
withArguments
(
"build"
,
"--parallel"
,
"--stacktrace"
).
withPluginClasspath
().
buildAndFail
();
assertThat
(
readLines
(
result
.
getOutput
())).
containsSequence
(
"Found test failures in 2 test tasks:"
,
""
,
assertThat
(
readLines
(
result
.
getOutput
())).
containsSequence
(
"Found test failures in 2 test tasks:"
,
""
,
":project-one:test"
,
" example.ExampleTests > bad()"
,
" example.ExampleTests > fail()"
,
":project-one:test"
,
" example.ExampleTests > bad()"
,
" example.ExampleTests > fail()"
,
" example.MoreTests > bad()"
,
" example.MoreTests > fail()"
,
""
,
":project-two:test"
,
" example.MoreTests > bad()"
,
" example.MoreTests > fail()"
,
""
,
":project-two:test"
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment