All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.gradle.build.event.BuildEventsIntegrationTest.groovy Maven / Gradle / Ivy

There is a newer version: 8.11.1
Show newest version
/*
 * Copyright 2019 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
 *
 *      http://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.gradle.build.event

import org.gradle.api.services.BuildServiceParameters
import org.gradle.integtests.fixtures.AbstractIntegrationSpec
import org.gradle.integtests.fixtures.InstantExecutionRunner
import org.gradle.tooling.events.FinishEvent
import org.gradle.tooling.events.OperationCompletionListener
import org.gradle.tooling.events.task.TaskFailureResult
import org.gradle.tooling.events.task.TaskFinishEvent
import org.gradle.tooling.events.task.TaskSkippedResult
import org.gradle.tooling.events.task.TaskSuccessResult
import org.junit.runner.RunWith

@RunWith(InstantExecutionRunner)
class BuildEventsIntegrationTest extends AbstractIntegrationSpec {
    def "listener can subscribe to task completion events"() {
        loggingListener()
        registeringPlugin()
        buildFile << """
            apply plugin: LoggingPlugin

            task notUpToDate {
                doFirst { println("not up-to-date") }
            }
            task upToDate {
                outputs.file("thing.txt")
                doFirst { file("thing.txt").text = "thing" }
            }
            task broken { 
                dependsOn notUpToDate, upToDate
                doFirst {
                    throw new RuntimeException()
                }
            }
        """

        when:
        run("notUpToDate")

        then:
        output.count("EVENT:") == 1
        outputContains("EVENT: finish :notUpToDate OK")

        when:
        run("notUpToDate")

        then:
        output.count("EVENT:") == 1
        outputContains("EVENT: finish :notUpToDate OK")

        when:
        fails("broken")

        then:
        output.count("EVENT:") == 3
        outputContains("EVENT: finish :notUpToDate OK")
        outputContains("EVENT: finish :upToDate OK")
        outputContains("EVENT: finish :broken FAILED")

        when:
        fails("broken")

        then:
        output.count("EVENT:") == 3
        outputContains("EVENT: finish :notUpToDate OK")
        outputContains("EVENT: finish :upToDate UP-TO-DATE")
        outputContains("EVENT: finish :broken FAILED")
    }

    def "plugin applied to multiple projects can register a shared listener"() {
        settingsFile << """
            include 'a', 'b'
        """
        loggingListener()
        registeringPlugin()
        buildFile << """
            subprojects {
                apply plugin: LoggingPlugin
                task thing { }
            }
        """

        when:
        run("a:thing")

        then:
        output.count("EVENT:") == 1
        outputContains("EVENT: finish :a:thing")

        when:
        run("a:thing")

        then:
        output.count("EVENT:") == 1
        outputContains("EVENT: finish :a:thing")

        when:
        run("thing")

        then:
        output.count("EVENT:") == 2
        outputContains("EVENT: finish :a:thing")
        outputContains("EVENT: finish :b:thing")

        when:
        run("thing")

        then:
        output.count("EVENT:") == 2
        outputContains("EVENT: finish :a:thing")
        outputContains("EVENT: finish :b:thing")
    }

    def "reports failure to handle event and continues with task execution"() {
        loggingListener()
        brokenListener()
        buildFile << """
            import ${BuildEventsListenerRegistry.name}

            def registry = project.services.get(BuildEventsListenerRegistry)
            registry.onTaskCompletion(gradle.sharedServices.registerIfAbsent('broken', BrokenListener) { })
            registry.onTaskCompletion(gradle.sharedServices.registerIfAbsent('listener', LoggingListener) { })

            task a 
            task b { dependsOn a }
        """

        when:
        fails("b")

        then:
        // TODO - add some context to the failure
        failure.assertHasDescription("broken")

        output.count("BROKEN:") == 1

        output.count("EVENT:") == 2
        outputContains("EVENT: finish :a")
        outputContains("EVENT: finish :b")

        when:
        fails("b")

        then:
        // TODO - add some context to the failure
        failure.assertHasDescription("broken")

        output.count("BROKEN:") == 1

        output.count("EVENT:") == 2
        outputContains("EVENT: finish :a")
        outputContains("EVENT: finish :b")
    }

    def "reports failure to create listener and continues with task execution"() {
        loggingListener()
        cannotConstructListener()
        buildFile << """
            import ${BuildEventsListenerRegistry.name}

            def registry = project.services.get(BuildEventsListenerRegistry)
            registry.onTaskCompletion(gradle.sharedServices.registerIfAbsent('broken', BrokenListener) { })
            registry.onTaskCompletion(gradle.sharedServices.registerIfAbsent('listener', LoggingListener) { })

            task a 
            task b { dependsOn a }
        """

        when:
        fails("b")

        then:
        // TODO - add some context to the failure
        failure.assertHasDescription("Failed to create service 'broken'.")
        failure.assertHasCause("broken")

        output.count("BROKEN:") == 1

        output.count("EVENT:") == 2
        outputContains("EVENT: finish :a")
        outputContains("EVENT: finish :b")

        when:
        fails("b")

        then:
        // TODO - add some context to the failure
        failure.assertHasDescription("Failed to create service 'broken'.")
        failure.assertHasCause("broken")

        output.count("BROKEN:") == 1

        output.count("EVENT:") == 2
        outputContains("EVENT: finish :a")
        outputContains("EVENT: finish :b")
    }

    def loggingListener() {
        buildFile << """
            import ${OperationCompletionListener.name}
            import ${FinishEvent.name}
            import ${TaskFinishEvent.name}
            import ${TaskSuccessResult.name}
            import ${TaskFailureResult.name}
            import ${TaskSkippedResult.name}
            import ${BuildServiceParameters.name}

            abstract class LoggingListener implements OperationCompletionListener, BuildService {
                @Override
                void onFinish(FinishEvent event) {
                    if (event instanceof TaskFinishEvent) {
                        print("EVENT: finish \${event.descriptor.taskPath}")
                        if (event.result instanceof TaskSuccessResult) {
                            if (event.result.upToDate) {
                                println(" UP-TO-DATE")
                            } else {
                                println(" OK")
                            }
                        } else if (event.result instanceof TaskFailureResult) {
                            println(" FAILED")
                        } else if (event.result instanceof TaskSkippedResult) {
                            println(" SKIPPED")
                        } else {
                            throw new IllegalArgumentException()
                        }
                    } else {
                        throw new IllegalArgumentException()
                    }
                }
            }
        """
    }

    def cannotConstructListener() {
        buildFile << """
            import ${OperationCompletionListener.name}
            import ${FinishEvent.name}
            import ${TaskFinishEvent.name}
            import ${TaskSuccessResult.name}
            import ${TaskFailureResult.name}
            import ${TaskSkippedResult.name}
            import ${BuildServiceParameters.name}

            abstract class BrokenListener implements OperationCompletionListener, BuildService {
                BrokenListener() {
                    println("BROKEN: created")
                    throw new RuntimeException("broken")
                }
                @Override
                void onFinish(FinishEvent event) {
                    println("BROKEN: received event") 
                }
            }
        """
    }

    def brokenListener() {
        buildFile << """
            import ${OperationCompletionListener.name}
            import ${FinishEvent.name}
            import ${TaskFinishEvent.name}
            import ${TaskSuccessResult.name}
            import ${TaskFailureResult.name}
            import ${TaskSkippedResult.name}
            import ${BuildServiceParameters.name}

            abstract class BrokenListener implements OperationCompletionListener, BuildService {
                @Override
                void onFinish(FinishEvent event) {
                    println("BROKEN: received event") 
                    throw new RuntimeException("broken")
                }
            }
        """
    }

    def registeringPlugin() {
        buildFile << """
            import ${BuildEventsListenerRegistry.name}
            import javax.inject.Inject

            abstract class LoggingPlugin implements Plugin {
                @Inject
                abstract BuildEventsListenerRegistry getListenerRegistry()

                void apply(Project project) {
                    def listener = project.gradle.sharedServices.registerIfAbsent("listener", LoggingListener) { }
                    listenerRegistry.onTaskCompletion(listener)
                }
            }
        """
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy