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

org.gradle.initialization.DefaultGradleLauncherSpec.groovy Maven / Gradle / Ivy

/*
 * Copyright 2016 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.initialization

import org.gradle.BuildListener
import org.gradle.StartParameter
import org.gradle.api.Task
import org.gradle.api.initialization.ProjectDescriptor
import org.gradle.initialization.exception.ExceptionAnalyser
import org.gradle.api.internal.GradleInternal
import org.gradle.api.internal.SettingsInternal
import org.gradle.api.internal.file.TestFiles
import org.gradle.api.internal.initialization.ClassLoaderScope
import org.gradle.api.internal.project.ProjectInternal
import org.gradle.api.internal.project.ProjectRegistry
import org.gradle.composite.internal.IncludedBuildControllers
import org.gradle.configuration.BuildConfigurer
import org.gradle.execution.BuildConfigurationActionExecuter
import org.gradle.execution.BuildExecuter
import org.gradle.execution.MultipleBuildFailures
import org.gradle.execution.taskgraph.TaskExecutionGraphInternal
import org.gradle.internal.concurrent.ParallelismConfigurationManagerFixture
import org.gradle.internal.concurrent.Stoppable
import org.gradle.internal.execution.history.ExecutionHistoryCacheAccess
import org.gradle.internal.operations.TestBuildOperationExecutor
import org.gradle.internal.resources.DefaultResourceLockCoordinationService
import org.gradle.internal.resources.ResourceLockCoordinationService
import org.gradle.internal.service.ServiceRegistry
import org.gradle.internal.service.scopes.BuildScopeServices
import org.gradle.internal.work.DefaultWorkerLeaseService
import org.gradle.internal.work.WorkerLeaseService
import org.gradle.test.fixtures.file.TestNameTestDirectoryProvider
import org.gradle.util.TestUtil
import spock.lang.Specification

import static org.gradle.util.Path.path

class DefaultGradleLauncherSpec extends Specification {
    def initScriptHandlerMock = Mock(InitScriptHandler)
    def settingsLoaderMock = Mock(SettingsLoader)
    def buildLoaderMock = Mock(BuildLoader)
    def taskGraphMock = Mock(TaskExecutionGraphInternal)
    def buildConfigurerMock = Mock(BuildConfigurer)
    def buildBroadcaster = Mock(BuildListener)
    def buildExecuter = Mock(BuildExecuter)
    def buildConfigurationActionExecuter = Mock(BuildConfigurationActionExecuter.class)
    def buildScopeServices = Mock(ServiceRegistry)
    def cacheAccess = Mock(ExecutionHistoryCacheAccess)

    private ProjectInternal expectedRootProject
    private ProjectInternal expectedCurrentProject
    private StartParameter expectedStartParams
    private SettingsInternal settingsMock = Mock(SettingsInternal.class)
    private GradleInternal gradleMock = Mock(GradleInternal.class)

    private ProjectDescriptor expectedRootProjectDescriptor

    private ClassLoaderScope baseClassLoaderScope = Mock(ClassLoaderScope.class)
    private ExceptionAnalyser exceptionAnalyserMock = Mock(ExceptionAnalyser)
    private ModelConfigurationListener modelListenerMock = Mock(ModelConfigurationListener.class)
    private BuildCompletionListener buildCompletionListener = Mock(BuildCompletionListener.class)
    private TestBuildOperationExecutor buildOperationExecutor = new TestBuildOperationExecutor()
    private ResourceLockCoordinationService coordinationService = new DefaultResourceLockCoordinationService()
    private WorkerLeaseService workerLeaseService = new DefaultWorkerLeaseService(coordinationService, new ParallelismConfigurationManagerFixture(true, 1))
    private BuildScopeServices buildServices = Mock(BuildScopeServices.class)
    private Stoppable otherService = Mock(Stoppable)
    private IncludedBuildControllers includedBuildControllers = Mock()
    public TestNameTestDirectoryProvider tmpDir = new TestNameTestDirectoryProvider()

    final RuntimeException failure = new RuntimeException("main")
    final RuntimeException transformedException = new RuntimeException("transformed")

    def setup() {
        boolean expectedSearchUpwards = false

        File expectedRootDir = tmpDir.file("rootDir")
        File expectedCurrentDir = new File(expectedRootDir, "currentDir")

        expectedRootProjectDescriptor = new DefaultProjectDescriptor(null, "someName", new File("somedir"), new DefaultProjectDescriptorRegistry(),
            TestFiles.resolver(expectedRootDir))
        expectedRootProject = TestUtil.createRootProject(expectedRootDir)
        expectedCurrentProject = TestUtil.createRootProject(expectedCurrentDir)

        expectedStartParams = new StartParameter()
        expectedStartParams.setCurrentDir(expectedCurrentDir)
        expectedStartParams.setSearchUpwards(expectedSearchUpwards)
        expectedStartParams.setGradleUserHomeDir(tmpDir.createDir("gradleUserHome"))

        _ * exceptionAnalyserMock.transform(failure) >> transformedException

        _ * settingsMock.getRootProject() >> expectedRootProjectDescriptor
        _ * settingsMock.getDefaultProject() >> expectedRootProjectDescriptor
        _ * settingsMock.getIncludedBuilds() >> []
        _ * settingsMock.getRootClassLoaderScope() >> baseClassLoaderScope
        _ * settingsMock.getProjectRegistry() >> Stub(ProjectRegistry)
        0 * settingsMock._

        _ * gradleMock.getRootProject() >> expectedRootProject
        _ * gradleMock.getDefaultProject() >> expectedCurrentProject
        _ * gradleMock.getTaskGraph() >> taskGraphMock
        _ * taskGraphMock.getRequestedTasks() >> [Mock(Task)]
        _ * taskGraphMock.getFilteredTasks() >> [Mock(Task)]
        _ * gradleMock.getStartParameter() >> expectedStartParams
        _ * gradleMock.getServices() >> buildScopeServices
        _ * gradleMock.includedBuilds >> []
        _ * gradleMock.getBuildOperation() >> null

        buildScopeServices.get(ExecutionHistoryCacheAccess) >> cacheAccess
        buildScopeServices.get(IncludedBuildControllers) >> includedBuildControllers
        buildServices.get(WorkerLeaseService) >> workerLeaseService
    }

    def cleanup() {
        workerLeaseService.stop()
    }

    DefaultGradleLauncher launcher() {
        return new DefaultGradleLauncher(gradleMock, initScriptHandlerMock, settingsLoaderMock, buildLoaderMock,
            buildConfigurerMock, exceptionAnalyserMock, buildBroadcaster,
            modelListenerMock, buildCompletionListener, buildOperationExecutor, buildConfigurationActionExecuter, buildExecuter,
            buildServices, [otherService], includedBuildControllers, null)
    }

    void testRunTasks() {
        when:
        isRootBuild()
        expectInitScriptsExecuted()
        expectSettingsBuilt()
        expectDagBuilt()
        expectTasksRun()
        expectBuildListenerCallbacks()
        DefaultGradleLauncher gradleLauncher = launcher()
        GradleInternal result = gradleLauncher.executeTasks()

        then:
        result == gradleMock
        expectedBuildOperationsFired()
    }

    void testRunAsNestedBuild() {
        when:
        isNestedBuild()

        expectInitScriptsExecuted()
        expectSettingsBuilt()
        expectDagBuilt()
        expectTasksRun()
        expectBuildListenerCallbacks()
        DefaultGradleLauncher gradleLauncher = launcher()
        GradleInternal result = gradleLauncher.executeTasks()

        then:
        result == gradleMock

        and:
        assert buildOperationExecutor.operations.size() == 5
        assert buildOperationExecutor.operations[0].displayName == "Load build (:nested)"
        assert buildOperationExecutor.operations[1].displayName == "Configure build (:nested)"
        assert buildOperationExecutor.operations[2].displayName == "Notify projectsEvaluated listeners (:nested)"
        assert buildOperationExecutor.operations[3].displayName == "Calculate task graph (:nested)"
        assert buildOperationExecutor.operations[4].displayName == "Run tasks (:nested)"
    }

    void testGetBuildAnalysis() {
        when:
        isRootBuild()
        expectInitScriptsExecuted()
        expectSettingsBuilt()
        expectBuildListenerCallbacks()

        1 * buildLoaderMock.load(settingsMock, gradleMock)
        1 * buildConfigurerMock.configure(gradleMock)

        DefaultGradleLauncher gradleLauncher = launcher()
        def result = gradleLauncher.getConfiguredBuild()

        then:
        result == gradleMock
    }

    void testNotifiesListenerOfBuildAnalysisStages() {
        when:
        isRootBuild()
        expectInitScriptsExecuted()
        expectSettingsBuilt()
        expectBuildListenerCallbacks()
        1 * buildConfigurerMock.configure(gradleMock)

        then:
        DefaultGradleLauncher gradleLauncher = launcher()
        gradleLauncher.getConfiguredBuild()
    }

    void testNotifiesListenerOfBuildStages() {
        when:
        isRootBuild()
        expectInitScriptsExecuted()
        expectSettingsBuilt()
        expectDagBuilt()
        expectTasksRun()
        expectBuildListenerCallbacks()

        then:
        DefaultGradleLauncher gradleLauncher = launcher()
        gradleLauncher.executeTasks()
    }

    void testNotifiesListenerOnBuildListenerFailure() {
        given:
        isRootBuild()
        1 * buildBroadcaster.buildStarted(gradleMock) >> { throw failure }
        1 * buildBroadcaster.buildFinished({ it.failure == transformedException })

        when:
        DefaultGradleLauncher gradleLauncher = launcher()
        gradleLauncher.executeTasks()

        then:
        def t = thrown RuntimeException
        t == transformedException
    }

    void testNotifiesListenerOnSettingsInitWithFailure() {
        given:
        isRootBuild()
        expectInitScriptsExecuted()

        and:
        1 * buildBroadcaster.buildStarted(gradleMock)
        1 * settingsLoaderMock.findAndLoadSettings(gradleMock) >> { throw failure }
        1 * buildBroadcaster.buildFinished({ it.failure == transformedException })

        when:
        DefaultGradleLauncher gradleLauncher = launcher()
        gradleLauncher.executeTasks()

        then:
        def t = thrown RuntimeException
        t == transformedException
    }

    void testNotifiesListenerOnBuildCompleteWithFailure() {
        given:
        isRootBuild()
        expectInitScriptsExecuted()
        expectSettingsBuilt()
        expectDagBuilt()
        expectTasksRunWithFailure(failure)

        and:
        1 * buildBroadcaster.buildStarted(gradleMock)
        1 * buildBroadcaster.projectsEvaluated(gradleMock)
        1 * modelListenerMock.onConfigure(gradleMock)
        1 * exceptionAnalyserMock.transform({ it instanceof MultipleBuildFailures && it.cause == failure }) >> transformedException
        1 * buildBroadcaster.buildFinished({ it.failure == transformedException })

        when:
        DefaultGradleLauncher gradleLauncher = launcher()
        gradleLauncher.executeTasks()

        then:
        def t = thrown RuntimeException
        t == transformedException
    }

    void testNotifiesListenerOnBuildCompleteWithMultipleFailures() {
        def failure2 = new RuntimeException()

        given:
        isRootBuild()
        expectInitScriptsExecuted()
        expectSettingsBuilt()
        expectDagBuilt()
        expectTasksRunWithFailure(failure, failure2)

        and:
        1 * buildBroadcaster.buildStarted(gradleMock)
        1 * buildBroadcaster.projectsEvaluated(gradleMock)
        1 * modelListenerMock.onConfigure(gradleMock)
        1 * exceptionAnalyserMock.transform({ it instanceof MultipleBuildFailures && it.causes == [failure, failure2] }) >> transformedException
        1 * buildBroadcaster.buildFinished({ it.failure == transformedException })

        when:
        DefaultGradleLauncher gradleLauncher = launcher()
        gradleLauncher.executeTasks()

        then:
        def t = thrown RuntimeException
        t == transformedException
    }

    void testTransformsBuildFinishedListenerFailure() {
        given:
        isRootBuild()
        expectInitScriptsExecuted()
        expectSettingsBuilt()
        expectDagBuilt()
        expectTasksRun()

        and:
        1 * buildBroadcaster.buildStarted(gradleMock)
        1 * buildBroadcaster.projectsEvaluated(gradleMock)
        1 * modelListenerMock.onConfigure(gradleMock)
        1 * buildBroadcaster.buildFinished({ it.failure == null }) >> { throw failure }
        1 * exceptionAnalyserMock.transform({ it instanceof MultipleBuildFailures && it.cause == failure }) >> transformedException

        and:
        DefaultGradleLauncher gradleLauncher = launcher()
        gradleLauncher.executeTasks()

        when:
        gradleLauncher.finishBuild()

        then:
        def t = thrown RuntimeException
        t == transformedException
    }

    void testNotifiesListenersOnMultipleBuildFailuresAndBuildListenerFailure() {
        def failure2 = new RuntimeException()
        def failure3 = new RuntimeException()
        def finalException = new RuntimeException()

        given:
        isRootBuild()
        expectInitScriptsExecuted()
        expectSettingsBuilt()
        expectDagBuilt()
        expectTasksRunWithFailure(failure, failure2)

        and:
        1 * buildBroadcaster.buildStarted(gradleMock)
        1 * buildBroadcaster.projectsEvaluated(gradleMock)
        1 * modelListenerMock.onConfigure(gradleMock)
        1 * exceptionAnalyserMock.transform({ it instanceof MultipleBuildFailures && it.causes == [failure, failure2] }) >> transformedException
        1 * buildBroadcaster.buildFinished({ it.failure == transformedException }) >> { throw failure3 }
        1 * exceptionAnalyserMock.transform({ it instanceof MultipleBuildFailures && it.causes == [failure, failure2, failure3] }) >> finalException

        and:
        DefaultGradleLauncher gradleLauncher = launcher()

        when:
        gradleLauncher.executeTasks()

        then:
        def t = thrown RuntimeException
        t == finalException
    }

    void testCleansUpOnStop() throws IOException {
        when:
        DefaultGradleLauncher gradleLauncher = launcher()
        gradleLauncher.stop()

        then:
        1 * buildServices.close()
        1 * otherService.stop()
        1 * buildCompletionListener.completed()
    }

    private void expectedBuildOperationsFired() {
        assert buildOperationExecutor.operations.size() == 5
        assert buildOperationExecutor.operations[0].displayName == "Load build"
        assert buildOperationExecutor.operations[1].displayName == "Configure build"
        assert buildOperationExecutor.operations[2].displayName == "Notify projectsEvaluated listeners"
        assert buildOperationExecutor.operations[3].displayName == "Calculate task graph"
        assert buildOperationExecutor.operations[4].displayName == "Run tasks"
    }

    private void isNestedBuild() {
        _ * gradleMock.parent >> Mock(GradleInternal)
        _ * gradleMock.findIdentityPath() >> path(":nested")
        _ * gradleMock.contextualize(_) >> {"${it[0]} (:nested)"}
    }

    private void isRootBuild() {
        _ * gradleMock.parent >> null
        _ * gradleMock.contextualize(_) >> { it[0] }
    }

    private void expectInitScriptsExecuted() {
        1 * initScriptHandlerMock.executeScripts(gradleMock)
    }

    private void expectSettingsBuilt() {
        1 * settingsLoaderMock.findAndLoadSettings(gradleMock) >> settingsMock
    }

    private void expectBuildListenerCallbacks() {
        1 * buildBroadcaster.buildStarted(gradleMock)
        1 * buildBroadcaster.projectsEvaluated(gradleMock)
        1 * modelListenerMock.onConfigure(gradleMock)
    }

    private void expectDagBuilt() {
        1 * buildConfigurerMock.configure(gradleMock)
        1 * buildConfigurationActionExecuter.select(gradleMock)
        1 * includedBuildControllers.populateTaskGraphs()
    }

    private void expectTasksRun() {
        1 * includedBuildControllers.startTaskExecution()
        1 * buildExecuter.execute(gradleMock, _)
        1 * includedBuildControllers.awaitTaskCompletion(_)
    }

    private void expectTasksRunWithFailure(Throwable failure, Throwable other = null) {
        1 * includedBuildControllers.startTaskExecution()
        1 * buildExecuter.execute(gradleMock, _) >> { GradleInternal g, List failures ->
            failures.add(failure)
        }
        1 * includedBuildControllers.awaitTaskCompletion(_) >> { List args ->
            if (other != null) {
                args[0].add(other)
            }
        }
        1 * includedBuildControllers.finishBuild(_)
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy