org.gradle.api.services.internal.DefaultBuildServicesRegistryTest.groovy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gradle-api Show documentation
Show all versions of gradle-api Show documentation
Gradle 6.9.1 API redistribution.
/*
* 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.api.services.internal
import org.gradle.BuildListener
import org.gradle.BuildResult
import org.gradle.api.Action
import org.gradle.api.GradleException
import org.gradle.api.artifacts.component.BuildIdentifier
import org.gradle.api.services.BuildService
import org.gradle.api.services.BuildServiceParameters
import org.gradle.internal.event.DefaultListenerManager
import org.gradle.internal.resources.SharedResourceLeaseRegistry
import org.gradle.internal.service.scopes.Scopes
import org.gradle.internal.snapshot.impl.DefaultValueSnapshotter
import org.gradle.util.TestUtil
import spock.lang.Specification
class DefaultBuildServicesRegistryTest extends Specification {
def listenerManager = new DefaultListenerManager(Scopes.Build)
def isolatableFactory = new DefaultValueSnapshotter(null, TestUtil.managedFactoryRegistry())
def leaseRegistry = Stub(SharedResourceLeaseRegistry)
def buildIdentifier = Mock(BuildIdentifier)
def registry = new DefaultBuildServicesRegistry(buildIdentifier, TestUtil.domainObjectCollectionFactory(), TestUtil.instantiatorFactory(), TestUtil.services(), listenerManager, isolatableFactory, leaseRegistry)
def setup() {
ServiceImpl.reset()
}
def "can lazily create service instance"() {
when:
def provider = registry.registerIfAbsent("service", ServiceImpl) {}
then:
ServiceImpl.instances.empty
when:
def service = provider.get()
then:
service instanceof ServiceImpl
ServiceImpl.instances == [service]
when:
def service2 = provider.get()
then:
service2.is(service)
ServiceImpl.instances == [service]
}
def "service provider always has value present"() {
when:
def provider = registry.registerIfAbsent("service", ServiceImpl) {}
then:
provider.present
ServiceImpl.instances.empty
}
def "wraps and memoizes service instantiation failure"() {
when:
def provider = registry.registerIfAbsent("service", BrokenServiceImpl) {}
then:
noExceptionThrown()
when:
provider.get()
then:
def e = thrown(RuntimeException)
e.message == "Failed to create service 'service'."
e.cause.cause.is(BrokenServiceImpl.failure)
BrokenServiceImpl.attempts == 1
when:
provider.get()
then:
def e2 = thrown(RuntimeException)
e2.is(e)
BrokenServiceImpl.attempts == 1
}
def "service has no max parallel usages by default"() {
expect:
registry.registerIfAbsent("service", ServiceImpl) {
assert !it.maxParallelUsages.present
}
def registration = registry.registrations.getByName("service")
!registration.maxParallelUsages.present
}
def "can locate registration by name"() {
when:
def provider = registry.registerIfAbsent("service", ServiceImpl) {}
def registration = registry.registrations.getByName("service")
then:
registration.service.is(provider)
ServiceImpl.instances.empty
}
def "reuses registration with same name"() {
when:
def provider1 = registry.registerIfAbsent("service", ServiceImpl) {}
def provider2 = registry.registerIfAbsent("service", ServiceImpl) {}
then:
provider1.is(provider2)
}
def "can provide parameters to the service"() {
when:
def provider = registry.registerIfAbsent("service", ServiceImpl) {
it.parameters.prop = "value"
}
def service = provider.get()
then:
service.prop == "value"
}
def "service can take no parameters"() {
def action = Mock(Action)
when:
def provider = registry.registerIfAbsent("service", NoParamsServiceImpl, action)
then:
1 * action.execute(_)
when:
def service = provider.get()
then:
service != null
}
def "can tweak parameters via the registration"() {
when:
def initialParameters
def provider = registry.registerIfAbsent("service", ServiceImpl) {
it.parameters.prop = "value 1"
initialParameters = it.parameters
}
def parameters = registry.registrations.getByName("service").parameters
then:
parameters.is(initialParameters)
parameters.prop == "value 1"
when:
parameters.prop = "value 2"
def service = provider.get()
then:
service.prop == "value 2"
}
def "can tweak max parallel usage via the registration"() {
when:
registry.registerIfAbsent("service", BuildService) {
it.maxParallelUsages = 42
}
def registration = registry.registrations.getByName("service")
then:
registration.maxParallelUsages.get() == 42
}
def "registration for service with no parameters is visible"() {
when:
registry.registerIfAbsent("service", NoParamsServiceImpl) {}
then:
registry.registrations.getByName("service") != null
}
def "can use base service type to create a service with no state"() {
when:
def provider = registry.registerIfAbsent("service", BuildService) {}
def service = provider.get()
then:
service instanceof BuildService
}
def "registration for service with no state is visible"() {
when:
registry.registerIfAbsent("service", BuildService) {}
then:
registry.registrations.getByName("service") != null
}
def "parameters are isolated when the service is instantiated"() {
given:
def provider = registry.registerIfAbsent("service", ServiceImpl) {
it.parameters.prop = "value 1"
}
def parameters = registry.registrations.getByName("service").parameters
def service = provider.get()
when:
parameters.prop = "ignore me 1"
then:
service.prop == "value 1"
when:
service.parameters.prop = "ignore me 2"
then:
parameters.prop == "ignore me 1"
}
def "stops service at end of build if it implements AutoCloseable"() {
def provider1 = registry.registerIfAbsent("one", ServiceImpl) {}
def provider2 = registry.registerIfAbsent("two", StoppableServiceImpl) {}
def provider3 = registry.registerIfAbsent("three", StoppableServiceImpl) {}
when:
def notStoppable = provider1.get()
def stoppable1 = provider2.get()
def stoppable2 = provider3.get()
then:
ServiceImpl.instances == [notStoppable, stoppable1, stoppable2]
when:
buildFinished()
then:
ServiceImpl.instances == [notStoppable]
}
def "does not attempt to stop an unused service at the end of build"() {
registry.registerIfAbsent("service", ServiceImpl) {}
when:
buildFinished()
then:
ServiceImpl.instances.empty
}
def "reports failure to stop service"() {
def provider = registry.registerIfAbsent("service", BrokenStopServiceImpl) {}
provider.get()
when:
buildFinished()
then:
def e = thrown(GradleException)
e.message == "Failed to stop service 'service'."
e.cause.is(BrokenStopServiceImpl.failure)
}
def "can locate resource corresponding to service registration"() {
when:
def service1 = registry.registerIfAbsent("service", BuildService) {
it.maxParallelUsages = 42
}
def service2 = registry.registerIfAbsent("no-max", ServiceImpl) {}
then:
registry.forService(service1).maxUsages == 42
registry.forService(service2).maxUsages == -1
}
def "cannot change max parallel usages once resource has been located"() {
given:
def service = registry.registerIfAbsent("service", ServiceImpl) {}
def registration = registry.registrations.findByName("service")
registration.maxParallelUsages = 42
registry.forService(service)
when:
registration.maxParallelUsages = 4
then:
def e = thrown(IllegalStateException)
e.message == "The value for property 'maxParallelUsages' is final and cannot be changed any further."
and:
registry.forService(service).maxUsages == 42
}
private buildFinished() {
listenerManager.getBroadcaster(BuildListener).buildFinished(Stub(BuildResult))
}
interface Params extends BuildServiceParameters {
String getProp()
void setProp(String value)
}
static abstract class ServiceImpl implements BuildService {
static List instances = []
String getProp() {
return getParameters().prop
}
static void reset() {
instances.clear()
}
ServiceImpl() {
instances.add(this)
}
}
static abstract class StoppableServiceImpl extends ServiceImpl implements AutoCloseable {
@Override
void close() {
instances.remove(this)
}
}
static abstract class NoParamsServiceImpl implements BuildService {
}
static abstract class BrokenServiceImpl implements BuildService {
static int attempts = 0
static RuntimeException failure = new RuntimeException("broken")
BrokenServiceImpl() {
attempts++
throw failure
}
}
static abstract class BrokenStopServiceImpl implements BuildService, AutoCloseable {
static int attempts = 0
static RuntimeException failure = new RuntimeException("broken")
@Override
void close() {
attempts++
throw failure
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy