org.gradle.internal.service.DefaultServiceRegistryTest.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 2013 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.internal.service
import org.gradle.api.Action
import org.gradle.internal.Factory
import org.gradle.internal.concurrent.Stoppable
import org.gradle.util.TextUtil
import spock.lang.Specification
import java.lang.reflect.Type
import java.util.concurrent.Callable
class DefaultServiceRegistryTest extends Specification {
def TestRegistry registry = new TestRegistry()
def throwsExceptionForUnknownService() {
when:
registry.get(StringBuilder.class)
then:
UnknownServiceException e = thrown()
e.message == "No service of type StringBuilder available in TestRegistry."
}
def delegatesToParentForUnknownService() {
def value = BigDecimal.TEN
def parent = Mock(ServiceRegistry)
def registry = new TestRegistry(parent)
when:
def result = registry.get(BigDecimal)
then:
result == value
and:
1 * parent.get(BigDecimal) >> value
}
def delegatesToParentsForUnknownService() {
def value = BigDecimal.TEN
def parent1 = Mock(ServiceRegistry)
def parent2 = Mock(ServiceRegistry)
def registry = new DefaultServiceRegistry(parent1, parent2)
when:
def result = registry.get(BigDecimal)
then:
result == value
and:
1 * parent1.get(BigDecimal) >> { throw new UnknownServiceException(BigDecimal, "fail") }
1 * parent2.get(BigDecimal) >> value
}
def throwsExceptionForUnknownParentService() {
def parent = Mock(ServiceRegistry);
def registry = new TestRegistry(parent)
given:
_ * parent.get(StringBuilder) >> { throw new UnknownServiceException(StringBuilder.class, "fail") }
when:
registry.get(StringBuilder)
then:
UnknownServiceException e = thrown()
e.message == "No service of type StringBuilder available in TestRegistry."
}
def returnsServiceInstanceThatHasBeenRegistered() {
def value = BigDecimal.TEN
def registry = new DefaultServiceRegistry()
given:
registry.add(BigDecimal, value)
expect:
registry.get(BigDecimal) == value
registry.get(Number) == value
registry.get(Object) == value
}
def createsInstanceOfServiceImplementation() {
def registry = new DefaultServiceRegistry()
registry.register({ ServiceRegistration registration ->
registration.add(TestServiceImpl)
} as Action)
expect:
registry.get(TestService) instanceof TestServiceImpl
registry.get(TestService) == registry.get(TestServiceImpl)
}
def injectsServicesIntoServiceImplementation() {
def registry = new DefaultServiceRegistry()
registry.register({ ServiceRegistration registration ->
registration.add(ServiceWithDependency)
registration.add(TestServiceImpl)
} as Action)
expect:
registry.get(ServiceWithDependency).service == registry.get(TestServiceImpl)
}
def usesFactoryMethodOnProviderToCreateServiceInstance() {
def registry = new DefaultServiceRegistry()
registry.addProvider(new TestProvider())
expect:
registry.get(Integer) == 12
registry.get(Number) == 12
}
def injectsServicesIntoProviderFactoryMethod() {
def registry = new DefaultServiceRegistry()
registry.addProvider(new Object() {
Integer createInteger() {
return 12
}
String createString(Integer integer) {
return integer.toString()
}
})
expect:
registry.get(String) == "12"
}
def injectsGenericTypesIntoProviderFactoryMethod() {
def registry = new DefaultServiceRegistry()
registry.addProvider(new Object() {
Integer createInteger(Factory factory) {
return factory.create().length()
}
Factory createString(Callable action) {
return { action.call() } as Factory
}
Callable createAction() {
return { "hi" }
}
})
expect:
registry.get(Integer) == 2
}
def handlesInheritanceInGenericTypes() {
def registry = new DefaultServiceRegistry()
registry.addProvider(new ProviderWithGenericTypes())
expect:
registry.get(Integer) == 123
}
def canHaveMultipleServicesWithParameterizedTypesAndSameRawType() {
def registry = new DefaultServiceRegistry()
registry.addProvider(new Object() {
Integer createInteger(Callable factory) {
return factory.call()
}
String createString(Callable factory) {
return factory.call()
}
Callable createIntFactory() {
return { 123 }
}
Callable createStringFactory() {
return { "hi" }
}
})
expect:
registry.get(Integer) == 123
registry.get(String) == "hi"
}
def injectsParentServicesIntoProviderFactoryMethod() {
def parent = Mock(ServiceRegistry)
def registry = new DefaultServiceRegistry(parent)
registry.addProvider(new Object() {
String createString(Number n) {
return n.toString()
}
})
when:
def result = registry.get(String)
then:
result == '123'
and:
1 * parent.get(Number) >> 123
}
def injectsGenericTypesFromParentIntoProviderFactoryMethod() {
def parent = new DefaultServiceRegistry() {
Callable createStringCallable() {
return { "hello" }
}
Factory createStringFactory() {
return { "world" } as Factory
}
}
def registry = new DefaultServiceRegistry(parent)
registry.addProvider(new Object() {
String createString(Callable callable, Factory factory) {
return callable.call() + ' ' + factory.create()
}
})
expect:
registry.get(String) == 'hello world'
}
def injectsServiceRegistryIntoProviderFactoryMethod() {
def parent = Mock(ServiceRegistry)
def registry = new DefaultServiceRegistry(parent)
registry.addProvider(new Object() {
String createString(ServiceRegistry services) {
assert services.is(registry)
return services.get(Number).toString()
}
})
registry.add(Integer, 123)
expect:
registry.get(String) == '123'
}
def failsWhenProviderFactoryMethodRequiresUnknownService() {
def registry = new DefaultServiceRegistry()
registry.addProvider(new StringProvider())
when:
registry.get(String)
then:
ServiceCreationException e = thrown()
e.message == "Cannot create service of type String using StringProvider.createString() as required service of type Runnable is not available."
when:
registry.get(Number)
then:
e = thrown()
e.message == "Cannot create service of type String using StringProvider.createString() as required service of type Runnable is not available."
}
def failsWhenProviderFactoryMethodThrowsException() {
def registry = new DefaultServiceRegistry()
registry.addProvider(new BrokenProvider())
when:
registry.get(String)
then:
ServiceCreationException e = thrown()
e.message == "Could not create service of type String using BrokenProvider.createString()."
e.cause == BrokenProvider.failure
when:
registry.get(Number)
then:
e = thrown()
e.message == "Could not create service of type String using BrokenProvider.createString()."
e.cause == BrokenProvider.failure
}
def cachesInstancesCreatedUsingAProviderFactoryMethod() {
def registry = new DefaultServiceRegistry()
def provider = new Object() {
String createString(Number number) {
return number.toString()
}
Integer createInteger() {
return 12
}
}
registry.addProvider(provider)
expect:
registry.get(Integer).is(registry.get(Integer))
registry.get(Number).is(registry.get(Number))
and:
registry.get(String).is(registry.get(String))
}
def usesProviderDecoratorMethodToDecorateParentServiceInstance() {
def parent = Mock(ServiceRegistry)
def registry = new DefaultServiceRegistry(parent)
registry.addProvider(decoratorProvider)
given:
_ * parent.get(Long) >> 110L
expect:
registry.get(Long) == 112L
registry.get(Number) == 112L
registry.get(Object) == 112L
where:
decoratorProvider << [ new TestDecoratingProviderWithCreate(), new TestDecoratingProviderWithDecorate() ]
}
def cachesServiceCreatedUsingProviderDecoratorMethod() {
def parent = Mock(ServiceRegistry)
def registry = new DefaultServiceRegistry(parent)
registry.addProvider(decoratorProvider)
given:
_ * parent.get(Long) >> 11L
expect:
registry.get(Long).is(registry.get(Long))
where:
decoratorProvider << [ new TestDecoratingProviderWithCreate(), new TestDecoratingProviderWithDecorate() ]
}
def conflictWhenCreateAndDecorateMethodDecorateTheSameType() {
def parent = Mock(ServiceRegistry)
def registry = new DefaultServiceRegistry(parent)
registry.addProvider(new ConflictingDecoratorMethods())
given:
_ * parent.get(Long) >> 11L
when:
registry.get(Long).is(registry.get(Long))
then:
ServiceLookupException e = thrown()
e.message.contains("Multiple services of type Long available in DefaultServiceRegistry:")
e.message.contains("- Service Long at ConflictingDecoratorMethods.createLong()")
e.message.contains("- Service Long at ConflictingDecoratorMethods.decorateLong()")
}
def providerDecoratorMethodFailsWhenNoParentRegistry() {
def registry = new DefaultServiceRegistry()
when:
registry.addProvider(decoratorProvider)
then:
ServiceLookupException e = thrown()
e.message == "Cannot use decorator method ${decoratorProvider.class.simpleName}.${methodName}Long() when no parent registry is provided."
where:
decoratorProvider | methodName
new TestDecoratingProviderWithCreate() | 'create'
new TestDecoratingProviderWithDecorate() | 'decorate'
}
def failsWhenProviderDecoratorMethodRequiresUnknownService() {
def parent = Stub(ServiceRegistry) {
get(_) >> { throw new UnknownServiceException(it[0], "broken") }
}
def registry = new DefaultServiceRegistry(parent)
given:
registry.addProvider(decoratorProvider)
when:
registry.get(Long)
then:
ServiceCreationException e = thrown()
e.message == "Cannot create service of type Long using ${decoratorProvider.class.simpleName}.${methodName}Long() as required service of type Long is not available in parent registries."
where:
decoratorProvider | methodName
new TestDecoratingProviderWithCreate() | 'create'
new TestDecoratingProviderWithDecorate() | 'decorate'
}
def failsWhenProviderDecoratorMethodThrowsException() {
def parent = Stub(ServiceRegistry) {
get(Long) >> 12L
}
def registry = new DefaultServiceRegistry(parent)
given:
registry.addProvider(decoratorProvider)
when:
registry.get(Long)
then:
ServiceCreationException e = thrown()
e.message == "Could not create service of type Long using ${decoratorProvider.class.simpleName}.${methodName}Long()."
e.cause == decoratorProvider.failure
where:
decoratorProvider | methodName
new BrokenDecoratingProviderWithCreate() | 'create'
new BrokenDecoratingProviderWithDecorate() | 'decorate'
}
def failsWhenThereIsACycleInDependenciesForProviderFactoryMethods() {
def registry = new DefaultServiceRegistry()
given:
registry.addProvider(new ProviderWithCycle())
when:
registry.get(String)
then:
ServiceCreationException e = thrown()
e.message == "Cannot create service of type Integer using ProviderWithCycle.createInteger() as there is a problem with parameter #1 of type String."
e.cause.message == 'Cycle in dependencies of service of type String.'
when:
registry.getAll(Number)
then:
e = thrown()
e.message == "Cannot create service of type Integer using ProviderWithCycle.createInteger() as there is a problem with parameter #1 of type String."
e.cause.message == 'Cycle in dependencies of service of type String.'
}
def failsWhenAProviderFactoryMethodReturnsNull() {
def registry = new DefaultServiceRegistry()
given:
registry.addProvider(new NullProvider())
when:
registry.get(String)
then:
ServiceCreationException e = thrown()
e.message == "Could not create service of type String using NullProvider.createString() as this method returned null."
}
def failsWhenAProviderDecoratorCreateMethodReturnsNull() {
def parent = Stub(ServiceRegistry) {
get(String) >> "parent"
}
def registry = new DefaultServiceRegistry(parent)
given:
registry.addProvider(decoratorProvider)
when:
registry.get(String)
then:
ServiceCreationException e = thrown()
e.message == "Could not create service of type String using ${decoratorProvider.class.simpleName}.${methodName}String() as this method returned null."
where:
decoratorProvider | methodName
new NullDecoratorWithCreate() | 'create'
new NullDecoratorWithDecorate() | 'decorate'
}
def usesFactoryMethodToCreateServiceInstance() {
expect:
registry.get(String.class) == "12"
registry.get(Integer.class) == 12
}
def cachesInstancesCreatedUsingAFactoryMethod() {
expect:
registry.get(Integer).is(registry.get(Integer))
registry.get(Number).is(registry.get(Number))
}
def usesOverriddenFactoryMethodToCreateServiceInstance() {
def registry = new TestRegistry() {
@Override
protected String createString() {
return "overridden"
}
};
expect:
registry.get(String) == "overridden"
}
def failsWhenMultipleFactoryMethodsCanCreateRequestedServiceType() {
def registry = new DefaultServiceRegistry();
registry.addProvider(new TestProvider())
expect:
registry.get(String)
when:
registry.get(Object)
then:
ServiceLookupException e = thrown()
e.message == TextUtil.toPlatformLineSeparators("""Multiple services of type Object available in DefaultServiceRegistry:
- Service Callable at TestProvider.createCallable()
- Service Factory at TestProvider.createTestFactory()
- Service Integer at TestProvider.createInt()
- Service String at TestProvider.createString()""")
}
def failsWhenArrayClassRequested() {
when:
registry.get(String[].class)
then:
ServiceLookupException e = thrown()
e.message == "Locating services with array type is not supported."
}
def cannotInjectAnArrayType() {
given:
registry.addProvider(new UnsupportedInjectionProvider())
when:
registry.get(Number)
then:
ServiceCreationException e = thrown()
e.message == "Cannot create service of type Number using UnsupportedInjectionProvider.create() as there is a problem with parameter #1 of type String[]."
e.cause.message == 'Locating services with array type is not supported.'
}
def usesDecoratorMethodToDecorateParentServiceInstance() {
def parent = Mock(ServiceRegistry)
def registry = decoratorCreator.call(parent) /* .call needed in spock 0.7 */
when:
def result = registry.get(Long)
then:
result == 120L
and:
1 * parent.get(Long) >> 110L
where:
decoratorCreator << [ { p -> new RegistryWithDecoratorMethodsWithCreate(p) }, { p -> new RegistryWithDecoratorMethodsWithDecorate(p) } ]
}
def decoratorCreateMethodFailsWhenNoParentRegistry() {
when:
decoratorCreator.call() /* .call needed in spock 0.7 */
then:
ServiceLookupException e = thrown()
e.message.matches(/Cannot use decorator method RegistryWithDecoratorMethodsWith(Create|Decorate)\..*\(\) when no parent registry is provided./)
where:
decoratorCreator << [ { new RegistryWithDecoratorMethodsWithCreate() }, { new RegistryWithDecoratorMethodsWithDecorate() } ]
}
def canRegisterServicesUsingAction() {
def registry = new DefaultServiceRegistry()
given:
registry.register({ ServiceRegistration registration ->
registration.add(Number, 12)
registration.add(TestServiceImpl)
registration.addProvider(new Object() {
String createString() {
return "hi"
}
})
} as Action)
expect:
registry.get(Number) == 12
registry.get(TestServiceImpl)
registry.get(String) == "hi"
}
def providerConfigureMethodCanRegisterServices() {
def registry = new DefaultServiceRegistry()
given:
registry.addProvider(new Object() {
void configure(ServiceRegistration registration, Number value) {
registration.addProvider(new Object() {
String createString() {
return value.toString()
}
})
}
Integer createNumber() {
return 123
}
})
expect:
registry.get(Number) == 123
registry.get(String) == "123"
}
def failsWhenProviderConfigureMethodRequiresUnknownService() {
def registry = new DefaultServiceRegistry()
when:
registry.addProvider(new NoOpConfigureProvider())
then:
ServiceLookupException e = thrown()
e.message == 'Cannot configure services using NoOpConfigureProvider.configure() as required service of type String is not available.'
}
def failsWhenProviderConfigureMethodFails() {
def registry = new DefaultServiceRegistry()
when:
registry.addProvider(new BrokenConfigureProvider())
then:
ServiceLookupException e = thrown()
e.message == 'Could not configure services using BrokenConfigureProvider.configure().'
e.cause == BrokenConfigureProvider.failure
}
def failsWhenCannotCreateServiceInstanceFromImplementationClass() {
given:
registry.register({ registration -> registration.add(ClassWithBrokenConstructor) } as Action)
when:
registry.get(ClassWithBrokenConstructor)
then:
ServiceCreationException e = thrown()
e.message == 'Could not create service of type ClassWithBrokenConstructor.'
e.cause == ClassWithBrokenConstructor.failure
}
def canGetAllServicesOfAGivenType() {
registry.addProvider(new Object() {
String createOtherString() {
return "hi"
}
})
expect:
registry.getAll(String) == ["12", "hi"]
registry.getAll(Number) == [12]
}
def canGetAllServicesOfARawType() {
def registry = new DefaultServiceRegistry()
registry.addProvider(new Object() {
String createString() {
return "hi"
}
Factory createFactory() {
return {} as Factory
}
Callable createCallable() {
return {}
}
})
expect:
registry.getAll(Factory).size() == 1
registry.getAll(Object).size() == 3
}
def allServicesReturnsEmptyCollectionWhenNoServicesOfGivenType() {
expect:
registry.getAll(Long).empty
}
def allServicesIncludesServicesFromParents() {
def parent1 = Stub(ServiceRegistry)
def parent2 = Stub(ServiceRegistry)
def registry = new DefaultServiceRegistry(parent1, parent2)
registry.addProvider(new Object() {
Long createLong() {
return 12;
}
});
given:
_ * parent1.getAll(Number) >> [123L]
_ * parent2.getAll(Number) >> [456]
expect:
registry.getAll(Number) == [12, 123L, 456]
}
def canGetServiceAsFactoryWhenTheServiceImplementsFactoryInterface() {
expect:
registry.getFactory(BigDecimal) instanceof TestFactory
registry.getFactory(Number) instanceof TestFactory
registry.getFactory(BigDecimal).is(registry.getFactory(BigDecimal))
registry.getFactory(Number).is(registry.getFactory(BigDecimal))
}
def canLocateFactoryWhenServiceInterfaceExtendsFactory() {
def registry = new DefaultServiceRegistry()
given:
registry.add(StringFactory, new StringFactory() {
public String create() {
return "value"
}
})
expect:
registry.getFactory(String.class).create() == "value"
}
def canGetAFactoryUsingParameterizedFactoryType() {
def registry = new RegistryWithMultipleFactoryMethods()
expect:
def stringFactory = registry.get(stringFactoryType)
stringFactory.create() == "hello"
def numberFactory = registry.get(numberFactoryType)
numberFactory.create() == 12
}
def canGetAFactoryUsingFactoryTypeWithBounds() throws NoSuchFieldException {
expect:
def superBigDecimalFactory = registry.get(superBigDecimalFactoryType)
superBigDecimalFactory.create() == BigDecimal.valueOf(0)
def extendsBigDecimalFactory = registry.get(extendsBigDecimalFactoryType)
extendsBigDecimalFactory.create() == BigDecimal.valueOf(1)
def extendsNumberFactory = registry.get(extendsNumberFactoryType)
extendsNumberFactory.create() == BigDecimal.valueOf(2)
}
def usesAFactoryServiceToCreateInstances() {
expect:
registry.newInstance(BigDecimal) == BigDecimal.valueOf(0)
registry.newInstance(BigDecimal) == BigDecimal.valueOf(1)
registry.newInstance(BigDecimal) == BigDecimal.valueOf(2)
}
def throwsExceptionForUnknownFactory() {
when:
registry.getFactory(String)
then:
UnknownServiceException e = thrown()
e.message == "No factory for objects of type String available in TestRegistry."
}
def delegatesToParentForUnknownFactory() {
def factory = Mock(Factory)
def parent = Mock(ServiceRegistry)
def registry = new TestRegistry(parent)
when:
def result = registry.getFactory(Map)
then:
result == factory
and:
1 * parent.getFactory(Map) >> factory
}
def usesDecoratorMethodToDecorateParentFactoryInstance() {
def factory = Mock(Factory)
def parent = Mock(ServiceRegistry)
def registry = decoratorCreator.call(parent) /* .call needed in spock 0.7 */
given:
_ * parent.getFactory(Long) >> factory
_ * factory.create() >>> [10L, 20L]
expect:
registry.newInstance(Long) == 12L
registry.newInstance(Long) == 22L
where:
decoratorCreator << [ { p -> new RegistryWithDecoratorMethodsWithCreate(p) } , { p -> new RegistryWithDecoratorMethodsWithDecorate(p) } ]
}
def failsWhenMultipleFactoriesAreAvailableForServiceType() {
def registry = new RegistryWithAmbiguousFactoryMethods()
when:
registry.getFactory(Object)
then:
ServiceLookupException e = thrown()
e.message == TextUtil.toPlatformLineSeparators("""Multiple factories for objects of type Object available in RegistryWithAmbiguousFactoryMethods:
- Service Factory
© 2015 - 2025 Weber Informatics LLC | Privacy Policy