org.gradle.execution.selection.DefaultBuildTaskSelectorTest.groovy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gradle-test-kit Show documentation
Show all versions of gradle-test-kit Show documentation
Gradle 6.2.1 API redistribution.
/*
* Copyright 2022 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.execution.selection
import org.gradle.api.Task
import org.gradle.api.internal.GradleInternal
import org.gradle.api.internal.project.ProjectInternal
import org.gradle.api.internal.project.ProjectState
import org.gradle.api.plugins.internal.HelpBuiltInCommand
import org.gradle.api.problems.internal.DefaultProblems
import org.gradle.api.problems.internal.NoOpProblemEmitter
import org.gradle.api.specs.Spec
import org.gradle.execution.ProjectSelectionException
import org.gradle.execution.TaskSelectionException
import org.gradle.execution.TaskSelector
import org.gradle.internal.Describables
import org.gradle.internal.build.BuildProjectRegistry
import org.gradle.internal.build.BuildStateRegistry
import org.gradle.internal.build.IncludedBuildState
import org.gradle.internal.build.RootBuildState
import org.gradle.internal.operations.CurrentBuildOperationRef
import org.gradle.util.Path
import spock.lang.Specification
import java.util.function.Consumer
class DefaultBuildTaskSelectorTest extends Specification {
def buildRegistry = Mock(BuildStateRegistry)
def taskSelector = Mock(TaskSelector)
def selector = new DefaultBuildTaskSelector(buildRegistry, taskSelector, [new HelpBuiltInCommand()], new DefaultProblems(new NoOpProblemEmitter(), Mock(CurrentBuildOperationRef)))
def root = rootBuild()
def target = root.state
def "fails on badly formed path"() {
when:
selector.resolveTaskName(null, null, target, path)
then:
def e = thrown(TaskSelectionException)
e.message == message
when:
selector.resolveExcludedTaskName(target, path)
then:
def e2 = thrown(TaskSelectionException)
e2.message == message
.replace("tasks that match", "excluded tasks that match")
.replace("matching tasks", "matching excluded tasks")
where:
path | message
"" | "Cannot locate matching tasks for an empty path. The path should include a task name (for example ':help' or 'help')."
":" | "Cannot locate tasks that match ':'. The path should include a task name (for example ':help' or 'help')."
"::" | "Cannot locate tasks that match '::'. The path should include a task name (for example ':help' or 'help')."
":::" | "Cannot locate tasks that match ':::'. The path should include a task name (for example ':help' or 'help')."
"a::b" | "Cannot locate tasks that match 'a::b'. The path should not include an empty segment (try 'a:b' instead)."
"a:b::c" | "Cannot locate tasks that match 'a:b::c'. The path should not include an empty segment (try 'a:b:c' instead)."
"a:" | "Cannot locate tasks that match 'a:'. The path should not include an empty segment (try 'a' instead)."
"a::" | "Cannot locate tasks that match 'a::'. The path should not include an empty segment (try 'a' instead)."
"::a" | "Cannot locate tasks that match '::a'. The path should not include an empty segment (try ':a' instead)."
":::a:b" | "Cannot locate tasks that match ':::a:b'. The path should not include an empty segment (try ':a:b' instead)."
" " | "Cannot locate matching tasks for an empty path. The path should include a task name (for example ':help' or 'help')."
": " | "Cannot locate tasks that match ': '. The path should include a task name (for example ':help' or 'help')."
"a: " | "Cannot locate tasks that match 'a: '. The path should not include an empty segment (try 'a' instead)."
"a: :b" | "Cannot locate tasks that match 'a: :b'. The path should not include an empty segment (try 'a:b' instead)."
" :a:b" | "Cannot locate tasks that match ' :a:b'. The path should not include an empty segment (try ':a:b' instead)."
" ::::a:b" | "Cannot locate tasks that match ' ::::a:b'. The path should not include an empty segment (try ':a:b' instead)."
}
def "selects matching tasks from default project and its subprojects when a name is provided"() {
when:
selector.resolveTaskName(null, null, target, "task")
then:
1 * taskSelector.getSelection(_, root.defaultProject, "task", true)
}
def "selects matching task relative to root project when absolute path is provided"() {
def project = addProject(root, "lib")
withIncludedBuilds()
when:
selector.resolveTaskName(null, null, target, ":task")
then:
1 * taskSelector.getSelection(_, root.rootProject, "task", false)
when:
selector.resolveTaskName(null, null, target, ":lib:task")
then:
1 * taskSelector.getSelection(_, project, "task", false)
}
def "selects matching task relative to default project when relative path is provided"() {
withIncludedBuilds()
when:
selector.resolveTaskName(null, null, target, "proj:task")
then:
1 * taskSelector.getSelection(_, root.defaultProject, "task", false)
}
def "selects matching task relative to root project of included build"() {
def other = includedBuild("build")
withIncludedBuilds(other)
when:
selector.resolveTaskName(null, null, target, ":build:task")
then:
1 * taskSelector.getSelection(_, other.rootProject, "task", false)
}
def "can use pattern matching to select project"() {
withIncludedBuilds()
def p1 = addProject(root, "someLibs")
def p2 = addProject(root, "otherLibs")
when:
selector.resolveTaskName(null, null, target, ":sL:task")
then:
1 * taskSelector.getSelection(_, p1, "task", false)
when:
selector.resolveTaskName(null, null, target, "pr:task")
then:
1 * taskSelector.getSelection(_, root.defaultProject, "task", false)
}
def "fails on unknown project"() {
withIncludedBuilds(includedBuild("proj1"))
addProject(root, "proj2")
addProject(root, "proj3")
when:
selector.resolveTaskName(null, null, target, path)
then:
def e = thrown(ProjectSelectionException)
e.message == message
where:
path | message
"unknown:task" | "Cannot locate tasks that match 'unknown:task' as project 'unknown' not found in ."
":unknown:task" | "Cannot locate tasks that match ':unknown:task' as project 'unknown' not found in ."
"progx:task" | "Cannot locate tasks that match 'progx:task' as project 'progx' not found in . Some candidates are: 'proj'."
}
def "fails on ambiguous project"() {
withIncludedBuilds(includedBuild("proj1"))
addProject(root, "proj2")
addProject(root, "proj3")
when:
selector.resolveTaskName(null, null, target, ":pr:task")
then:
def e = thrown(ProjectSelectionException)
e.message == "Cannot locate tasks that match ':pr:task' as project 'pr' is ambiguous in . Candidates are: 'proj', 'proj1', 'proj2', 'proj3'."
}
def "lazily resolves an exclude name to tasks in the target build"() {
when:
def filter = selector.resolveExcludedTaskName(target, "task")
then:
filter.build == target
and:
0 * target.ensureProjectsConfigured()
0 * taskSelector._
when:
filter.filter.isSatisfiedBy(Stub(Task))
then:
1 * taskSelector.getFilter(_, root.defaultProject, "task", true) >> Stub(Spec)
0 * taskSelector._
}
def "lazily resolves an exclude relative path to a task in the target build"() {
when:
def filter = selector.resolveExcludedTaskName(target, "proj:task")
then:
filter.build == target
and:
0 * target.ensureProjectsConfigured()
0 * taskSelector._
when:
filter.filter.isSatisfiedBy(Stub(Task))
then:
1 * taskSelector.getFilter(_, root.defaultProject, "task", false) >> Stub(Spec)
0 * taskSelector._
}
def "lazily resolves an exclude absolute path to a task in another build"() {
def other = includedBuild("build")
withIncludedBuilds(other)
when:
def filter = selector.resolveExcludedTaskName(target, ":build:task")
then:
filter.build == other.state
and:
0 * target.ensureProjectsConfigured()
0 * taskSelector._
when:
filter.filter.isSatisfiedBy(Stub(Task))
then:
1 * taskSelector.getFilter(_, other.rootProject, "task", false) >> Stub(Spec)
0 * taskSelector._
}
def "lazily resolves an exclude absolute path to a task in the target build when prefix does not match any build"() {
def other = includedBuild("build")
withIncludedBuilds(other)
when:
def filter = selector.resolveExcludedTaskName(target, ":proj:task")
then:
filter.build == target
and:
0 * target.ensureProjectsConfigured()
0 * taskSelector._
when:
filter.filter.isSatisfiedBy(Stub(Task))
then:
1 * taskSelector.getFilter(_, root.defaultProject, "task", false) >> Stub(Spec)
0 * taskSelector._
}
private void withIncludedBuilds(IncludedBuildFixture... builds) {
_ * buildRegistry.visitBuilds(_) >> { Consumer visitor ->
visitor.accept(root.state)
for (final def build in builds) {
visitor.accept(build.state)
}
}
}
private RootBuildFixture rootBuild() {
def build = Mock(RootBuildState)
def projects = Mock(BuildProjectRegistry)
def gradle = Mock(GradleInternal)
def defaultProject = Mock(ProjectInternal)
def defaultProjectState = Mock(ProjectState)
def rootProjectState = Mock(ProjectState)
build.projectsCreated >> true
build.mutableModel >> gradle
gradle.defaultProject >> defaultProject
defaultProject.owner >> defaultProjectState
defaultProjectState.name >> "proj"
defaultProjectState.displayName >> Describables.of("")
defaultProjectState.projectPath >> Path.path(":proj")
defaultProjectState.identityPath >> Path.path(":proj")
defaultProjectState.owner >> build
defaultProjectState.childProjects >> [defaultProjectState].toSet()
buildRegistry.rootBuild >> build
def rootChildProjects = [].toSet()
rootChildProjects.add(defaultProjectState)
build.projects >> projects
projects.rootProject >> rootProjectState
projects.allProjects >> [rootProjectState]
rootProjectState.name >> "root"
rootProjectState.displayName >> Describables.of("")
rootProjectState.projectPath >> Path.ROOT
rootProjectState.identityPath >> Path.ROOT
rootProjectState.owner >> build
rootProjectState.childProjects >> rootChildProjects
rootProjectState.created >> true
return new RootBuildFixture(build, rootProjectState, rootChildProjects, defaultProjectState)
}
private IncludedBuildFixture includedBuild(String name) {
def build = Mock(IncludedBuildState)
def projects = Mock(BuildProjectRegistry)
def rootProject = Mock(ProjectState)
_ * build.name >> name
_ * build.projects >> projects
_ * build.importableBuild >> true
_ * build.projectsLoaded >> true
_ * projects.rootProject >> rootProject
_ * rootProject.projectPath >> Path.ROOT
_ * rootProject.identityPath >> Path.path(":${name}")
_ * rootProject.owner >> build
return new IncludedBuildFixture(build, rootProject)
}
private ProjectState addProject(RootBuildFixture build, String name) {
def projectState = Mock(ProjectState)
projectState.projectPath >> Path.path(":$name")
projectState.identityPath >> Path.path(":$name")
projectState.owner >> build.state
build.rootChildProjects.add(projectState)
return projectState
}
class IncludedBuildFixture {
final IncludedBuildState state
final ProjectState rootProject
IncludedBuildFixture(IncludedBuildState state, ProjectState rootProject) {
this.state = state
this.rootProject = rootProject
}
}
class RootBuildFixture {
final RootBuildState state
final ProjectState rootProject
final ProjectState defaultProject
final Set rootChildProjects
RootBuildFixture(RootBuildState state, ProjectState rootProject, Set rootChildProjects, ProjectState defaultProject) {
this.state = state
this.rootProject = rootProject
this.rootChildProjects = rootChildProjects
this.defaultProject = defaultProject
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy