run stop tomcat task if test task fails in gradle project - java

I am working on a gradle project. I have written few tests for it.
In build.gradle, I have written three tasks for it: tomcatStart, tomcatEnd and test.
Inside test task, i am executing tomcatStart in doFirst and tomcatStop in doLast.
It all works fine if there is no test failure.
But if a test fails, the tomcat keeps on running.
I want to know if there is any way, i can stop tomcat even if test task fails.

Try to use finalizebBy property of the test task. It's well described in the official documentation. According to it:
Finalizer tasks are useful in situations where the build creates a resource that has to be cleaned up regardless of the build failing or succeeding. An example of such a resource is a web container that is started before an integration test task and which should be always shut down, even if some of the tests fail.
And here is an example from the docs:
task taskX {
doLast {
println 'taskX'
throw new RuntimeException()
}
}
task taskY {
doLast {
println 'taskY'
}
}
taskX.finalizedBy taskY

Related

Gradle override the default check task

I've defined my sourceSets as
sourceSets {
// Configuring SourceSets for all connector source files.
main {
java {
srcDirs = ['src']
}
}
test {
// integrationTests
}
unitTests {
//unitTests
}
}
test {
// integrationTests
}
task('unitTest', type: Test) {
//unitTests
}
When I kick off ./gradlew build it's check task basically calls the test target.
Can I override the default gradle build tasks's 'check' mechanism to call unitTest here instead of test?
First of all, please consider just using the task test for unit tests and using another source set for integration tests. Gradle and its plugins follow an approach called convention over configuration and the convention of the Java plugin is to use the task test for unit tests.
To actually answer your question, you can access and modify the dependencies of each task using getDependsOn() and setDependsOn​(Iterable<?>), so a simple solution to your problem could be the following code:
check {
dependsOn.clear()
dependsOn unitTest
}
This removes all task dependencies from the task check and then adds a dependency on the task unitTest. However, this may cause new problems, because other plugins may automatically register task dependencies for check that will be removed, too.
An obvious improvement to the code above would be to just remove the dependency on the test task instead of all task dependencies. Sadly, this is not as simple as one would think. You may have noticed that the method getDependsOn() returns a Set<Object> and not a Set<Task>. For convenience, task dependencies may be expressed not only using tasks but also by passing other objects that will resolve to tasks later on (e.g. a string containing the name of a task). The current version of the Java plugin uses a Provider<Task> to register the dependency between the task check and the task test. To just remove the dependency on the task test, you would need to iterate over all dependencies in dependsOn and find the one with the type Provider that returns the task test via its get() method. You could then remove that Provider from dependsOn.
As you can see, it is possible to remove task dependencies once they have been registered, but it is not that easy, so you should probably just follow the convention and use the task test for unit tests.

gradle WriteProperties task does not create properties file unless the task is ran directly

I am trying to generate properties files in a non-Android Java project, but for some reason even though the task runs when I build the project with ./gradlew assembleDist or run it with ./gradlew foo:run, the properties file isn't created. The task is defined in a subproject and looks like this:
task writeProperties(type: WriteProperties) {
outputFile 'src/main/resources/foo.properties'
property 'version', version
property 'releaseType', releaseType
property 'date', date
println("task ran")
}
task ran gets printed when I execute the other gradle tasks, indicating that the task ran, but no foo.properties file shows up in the specified path. Weirdly enough, if I run the writeProperties task directly with ./gradlew foo:writeProperties, the file gets created and populated with the correct variables.
I've tried wrapping the statements above with doFirst{} and doLast{} but I get errors like the following:
Cause: path may not be null or empty string. path='null'
Does anyone have any idea what I could be doing wrong? I've been banging my head against this for hours and am running out of ideas. Thanks!
update: I managed to solve it with information provided in the accepted answer. I had to add compileJava.finalizedBy(writeProperties) to get the task to actually run as part of the build tasks. As the top answer mentioned, println was essentially lying to me, as that was being printed during the configuration phase but the task action was not being ran.
The actual problem with your code is that your println statement is not telling the truth. The code in the task configuration closure runs when the task gets configured, not when it gets executed. So everytime you run another task from the command line, your task gets configured and the println writes to the command line, but the actual task action is not executed. You should pack your println into a doLast, so that it actually runs after the .properties file has been created.
task myTask {
println 'task configured'
doLast {
println 'task executed'
}
}
If you want your task to run without specifying it on the command line, you need to setup task dependencies using dependsOn or finalizedBy.
The described issue is not a problem. What's happening is exactly how Gradle works. I too have struggled with understanding why this behavior is correct! I'm providing an answer to help bring some clarity as to what's going on. Algebo is not alone in trying to understand how Gradle works. Algebo did a great job in describing what he observed and hopefully my answer takes out some of the mystery of what's going on.
First thing to understand is that gradle evaluates the code in three passes: initialization, configuration and execution.
During initialization, gradle figures out which projects are to be included in the build.
During configuration, the tasks are created and configured and added to the build graph. When a task is configured, you need to tell gradle what are the inputs and outputs to the task. Gradle uses that information to know whether it actually needs to execute the task or not. (i.e. if the inputs and outputs of a task is up-to-date, then you can skip the execution of the task)
During execution, gradle then executes the actions associated with task.
With the above explanation, let's look at what's happening with Algebo's code. The first thing that Algebo notices is that he sees the "task ran" message. So why was that? That's because that code was executed during the gradle configuration phase. (Lukas answer does a good job explaining this same observation) So, all that's done at this time is that the "writeProperties" task object (which is of type "WriteProperties") get configured. And of course, Algrebo correctly notices that the "foo.properties" file was not created. And that of course is because the task was only configured and not yet execute.
The next thing Algebo tries is to put the code in the task block in a doFirst and a doLast block. When Algebo tries that, he gets the error message that the path may be null or empty. The doFirst and doLast the blocks of code that define a task action. As I stated earlier, it the task actions that get executed during the task execution pass. So why does Algebo get that error. In the case of the "WriteProperties" task, it requires that the "outputFile" to be configured. But, Algebo moved the outputFile statement to a task action block. In other words, the outputFile has not been defined at the time either the doFirst or doLast code gets executed. The "WriteProperties" task needs that define prior to the task actions being performed. So that explains that observed behavior.
So why does it work when he executes the task directly using ./gradlew foo:writeProperties directly. Well, that's because the task is properly configured, and when he executes it directly, it executes the task actions associated with the task. Well, Algebo didn't define any task actions, so there's none to be executed, and once the task actions have completed (none), the WriteProperies task concludes by writing of the defined properties to the outputFile. And that's of course what Algebo observed.
And lastly, Algebo noticed that he could get the task to do what he wanted to by adding the statement: compileJava.finalizedBy(writeProperties). In that case, the WiteProperties task has been configured. Additionally during the configuration pass, that task was added to the build graph. In other words, that task was configured to be run when the "compileJava" task completed. When the "writeProperties" task is executed, it has been properly configured, so it executes the task actions for the task (none in this case) and when done the "WriteProperties" task concludes by writing the properties to the "outputFile".
With all the above said, there's still another issue with the "writeProperties" task as defined. Gradle now wants user to define the inputs and outputs of all tasks. Gradle uses that imformation to determine whether a task needs to be executed or skipped if it already up-to-date. In Algebo's example, the inputs are: "version", "releaseType" and "date" and the outputs are the file "src/main/resources/foo.properties". (Note: gradle doesn't know that "outputFile" is part of "outputs"). The "writeProperties" task doesn't have its inputs and outputs configured. So "writeProperties" will always get executed even if nothing has changed since it was last executed. In Algebo final working solution, his properties file would not get rebuilt if for example "version" changed and the compileJava task was already up-to-date.
For additional information, I found this to be helpful.
generate new code in the build folder (not main source)
add the generated files to the source set
link new task to the build chain
ext.genRes = 'build/generated_src/main/resources'
sourceSets {
main {
resources {
srcDir(genRes)
}
}
}
ext.genResFoo = genRes + 'foo.properties'
ext.releaseType = 'test'
task genResources(type: WriteProperties) {
outputFile genResFoo
property 'version', version
property 'releaseType', releaseType
property 'date', new java.util.Date()
doLast {
println("writeProperties ran ${genResFoo}")
}
}
processResources.dependsOn genResources

How do I make an alias for a Gradle task?

As a part of a TDD workflow, I want to be able to check if my Java codebase compiles, but not if the tests pass.
Currently, if I run gradle build it runs the compile tasks (for source and tests) and then also executes the test task (and returns a non-zero exit code since the tests fail).
So I find that I have to run gradle build -x test to exclude the test task, and get a successful zero exit code.
What do I add to my build.gradle to define a new task, say compile that is an alias for build x test?
So far I have this, but it doesn't seem like dependsOn takes any arguments to customize the build task I want to execute:
task compile {
dependsOn build
}
I've been reading the docs here, I see different kinds of dependency chaining mechanisms, but not to disable/exclude a particular task. How does the -x flag even work then? I assumed there would be a way to control it programmatically too.
Thanks to Bjørn Vester's answer and reading the docs, I have implemented my task as follows:
task compile {
dependsOn classes
dependsOn testClasses
}
There are lots of different tasks you can run individually. For instance:
gradle classes: Will compile your "main" code.
gradle testClasses: Will compile your "main" code as well as test code.
gradle jar: Will compile your "main" code and assemble it into a jar.
None of the above will run your unit tests. On the other hand, the build task depends on all of the above, as well as the test task and more.
In general, if you like to run a particular set of tasks, you do that by defining a new task and then make dependencies to those other tasks you like to run with it. You tried that already, but instead of build you should have used something like compileJava or classes whatever other tasks you need. But always check if there isn't one already that satisfies your needs, like there are in this case. You can read about what tasks are available in Java projects in the documentation for the Gradle java plugin.

How to run integration task after run task in gradle?

My Application is Spring boot application exposing some rest api
To run my integration tests , , first the application need to be up and running , as my application gradle based , how to make sure when i execute gradle command from command prompt , first application run and the integration tests will run .
task integration(type: Test, description: 'Runs the integration tests.', group: 'Verification') {
testClassesDir = sourceSets.integration.output.classesDir
classpath = sourceSets.integration.runtimeClasspath
outputs.upToDateWhen { false }
}
task appRunAndIntegrtationTest {
dependsOn 'run'
dependsOn 'integration'
tasks.findByName('integration').mustRunAfter 'run'
}
i added above code to build.gradle , but application up and running , thats it , it stayed their only , integration tests are not running , can anyone has idea on this please .
update : #Strelok , as mentioned , the application started up and integration task is not running .
update 1 : i found one gradle plugin
https://github.com/marc0der/gradle-spawn-plugin
i am trying to use like below
task startServer(type: SpawnProcessTask, dependsOn: 'assemble') {
command "java -jar ${projectDir}/build/libs/example.jar"
ready 'Started Application'
}
task stopServer(type: KillProcessTask)
but am getting below exception
*> Could not get unknown property 'SpawnProcessTask' for root project 'example-api' of type org.gradle.api.Project.
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.*
please someone please suggest on this
I suggest a different approach: start and stop your application from your test framework. Test frameworks support setup and cleanup steps for your test suite (e.g. BeforeClass and AfterClass in JUnit), start the application in the setup step and stop it in the cleanup step. This approach will make your tests more self-contained, their success/failure will not depend on factors outside the test code.
Even if you prefer to run the application outside the test framework, I suggest wrapping this logic (i.e. starting the app, running the tests, stopping the app) in a Java class, and executing this class from Gradle via a task of type JavaExec. It will be much more clear than handling all this via Gradle tasks.
Finally, if you still insist on Gradle tasks, it's like the commenters said: the "run" task probably blocks execution while the app is running. Tha only sane way to handle this is to have a task that starts the app in the background, and another that stops it after the tests finished (use finalizedBy).
You should declare that the integration test task needs to depend on your app run task.
appRun is just an example please use the name of the task that is the precursor for the integration test.
integration.dependsOn appRun
integration.mustRunAfter appRun
Also, it might be like your app is running and blocking the progress of your Gradle build, does the build actually finish or it just hangs until the app stops running?

Execute gradle task when its dependency is still running

I have to run a jar file and exec npm tests on it, but using gradle tasks. I'm using dependsOn to run the npm test after the jar is running.
These are my gradle tasks:
task runServer1 (type: Exec) {
// Run the jar file
}
task runNpmTest (type: Exec, dependsOn: ':runServer1') {
// Run npm tests
}
The problem is that when I execute gradle runNpmTest gradle stops at runServer1, which makes sense, because the server is still running. But my NPM tests will never run.
Any ideas?
It will not work this way, since runServer1 task is still running - it's a process. What you need is to run a server in background - so it won't block the main thread - and then run the tests. This probably should be done in a single task and configured via actions. Please have a look here and here to catch some useful knowledge.

Categories

Resources