Integration tests in spring boot application with spring cloud - spring-boot

I have an spring-boot application that uses config server.
In project I have a bootstrap.yml:
spring:
cloud:
config:
uri: ${CLOUD_CONFIG_URI:http://localhost:8888}
failFast: true
enabled: ??
and I can pass actual config for server location through parameter. That's ok.
With this configuration I don't know how to disable this in integration tests. My tests load this configuration and want to communicate with config server. I know that I can pass spring.cloud.config.enabled=false but it's not a solution (I want to right click in IDE and run test without additional configuration per each test method).
Any idea?

This is a late answer but for the people that join from any search engines here is my solution:
The #Profile("test") annotation above your integration test class is correct. To get this really working is adding two extra configuration files to your normal resources folder, not the test resources folder.
Add "application-test.yml"
Add "bootstrap-test.yml"
In your bootstrap-test.yml add the following:
spring:
cloud:
config:
enabled: false
With this configuration you can put all of your needed configuration options in the application-test.yml and the bootstrap-test.yml will disabled spring cloud config.

Related

Spring-Boot: How to load a keystore resource file either from the classpath or from the file system?

My spring-boot application requires access to private keys via a Java keystore. For testing, I would like to use a test keystore that is available on the classpath (so I can easily execute the application as part of an integration test), while in production I would like to use a keystore from some external volume (e.g., mounted inside a container as k8 secret).
I know that the spring-boot #Value annotation allows me to inject a resource. However, I don't see how it can be made dynamic to respect the spring environment (e.g., test or production). Does spring-boot provide an out-of-the-box way to solve the above problem, or do I need to write my own bean to load the correct keystore depending on the deployment environment?
You can use a property for the resource path and set that property values in your application props differently based on an active profile.
#Value("${my.resource.path:#{null}}")
private Resource myResource;
application.yml:
spring:
config:
activate:
on-profile: test
my.resource.path: 'classpath:test/path/keystore.jks'
---
spring:
config:
activate:
on-profile: prod
my.resource.path: 'file:prod/path/keystore.jks'

Spring Cloud Embedded Config Server with native repository

I have a working spring boot application and I am trying to remove some properties from application.yaml file and read them from an embedded config server in the same app. At the moment, I am trying to read properties from file system through "native" profile type, and I am planning to later replace this with S3. Also, I am trying to read the configuration directly from backend repository as explained here https://docs.spring.io/spring-cloud-config/docs/current/reference/html/#_embedding_the_config_server , rather than connecting through an endpoint.
If you want to read the configuration for an application directly from
the backend repository (instead of from the config server), you
basically want an embedded config server with no endpoints. You can
switch off the endpoints entirely by not using the #EnableConfigServer
annotation (set spring.cloud.config.server.bootstrap=true).
I have introduced following changes to my existing application to achieve this.
Added following dependencies to pom.xml
spring-cloud-starter-config
spring-cloud-config-server
spring-cloud-config-client
application-dev.yaml
spring:
could:
bootstrap:
enabled: true
bootstrap.yaml
spring:
profiles:
active: composite
cloud:
config:
server:
composite:
- type: native
search-locations: file:C:\\Users\\chamila\\config-test\\config
# bootstrap: true
The required properties are saved in a different application-dev.yaml file at the above file path. I have not used #EnableConfigServer annotation from my app class, as I want connect directly without the endpoint.
However, still my program is failing to read the properties from the config-server. I tried setting spring.cloud.config.server.bootstrap=true and spring.cloud.bootstrap.enabled=true from both application-dev.yaml and bootstrap.yaml, but it didn't work?
Any idea what I am missing? I note that I never specified how to connect to the config-server in my application-dev.yaml file also. Is that an issue?
Any help is highly appreciated.
I created a sample project of an embedded Configuration Server which uses a custom repository:
https://github.com/taxone/embedded-config-server
The initial problem was that the custom EnvironmentRepository was not available via bootstrap, as described in this issue.
I followed https://cloud.spring.io/spring-cloud-config/reference/html/#_embedding_the_config_server and achieved the expected result.
Add spring-cloud-starter-bootstrap to your dependencies as suggested in https://github.com/taxone/embedded-config-server.
Make sure that composite profile is active when you start the app.
Verify that your native configuration is added by finding a log message from NativeEnvironmentRepository during startup.
(Optional) Remove spring.cloud.bootstrap.enabled from application-dev.yaml.
(Optional) Remove spring-cloud-config-client dependency as it is included in both spring-cloud-starter-config and
spring-cloud-config-server.
(Further steps) Use #RefreshScope on a spring bean to achieve dynamic properties. Requires POST actuator/refresh.

How to override a property defined in profile-specific application-{profile}.yml for a single application?

I have a spring-cloud-config server set up to serve YML files from a git repository. The server is using Spring Cloud 2020.0.3. There are several spring-cloud-config clients consuming config files from the server. The client applications consuming the config are using Spring Boot 2.4.6 and the new config parsing implementation.
The config repository contains an application-db.yml file and myapp.yml file. The application-db.yml file has several common properties set that all applications will use for the db profile. myapp.yml has properties for a specific application. Prior to using Spring Boot 2.4.6, I was able to override properties from application-db.yml in myapp.yml. In effect, the application-db.yml properties were the default values that individual applications could override.
For example application-db.yml might have (property key is not relevant):
spring:
datasource:
hikari:
maximum-pool-size: 5
to set the connection pool size to 5 for most applications and myapp.yml could set
spring:
datasource:
hikari:
maximum-pool-size: 10
for a one-off connection pool size of 10.
In Spring Cloud 2020.0.3 (Spring Cloud Config 3.0.4) and Spring Boot 2.4.6, the behavior is that the property in application-db.yml cannot be overridden in myapp.yml and the connection pool size property always has value 5.
I have tried setting the following properties in the application.yml and still have the same results.
spring:
cloud:
config:
allowOverride: true
overrideNone: true
overrideSystemProperties: false
According to Config file processing in Spring Boot 2.4 overriding property values is allowed in the config processing, but it is dependent on document order.
Is the overriding behavior still supported by Spring Boot using Spring Cloud Config? If so, does it depend on the order the cloud config server serves the documents? Is there a way to control the order?
edit note: I originally posted about overriding properties in the application.yml file. After more investigation, that does allowing overriding. It is in the profile specific files like application-db.yml that I cannot override values. I'm starting to think this might be a bug.
The overriding behavior you are looking for is supported in the latest release documented here and should be the default behavior without needing to add additional properties to enable override. You will need to include the application name with the spring.application.name property for the config server to recognize the overriding file.The overriding file also needs to have the same name you give in the client application (in this case,for example, my config repo has files application.properties and myapp.properties.
Client application.properties
spring.application.name=myapp
spring.config.import=optional:configserver:http://localhost:8888
...
Server application.properties
spring.application.name=configserver
spring.cloud.config.server.git.uri=https://github.com/...
server.port=8888
...
Within config repo
application.properties
spring:
datasource:
hikari:
maximum-pool-size: 5
myapp.properties
spring:
datasource:
hikari:
maximum-pool-size: 10
If the client application cannot fetch the overriding file (in this case the myapp file) from the config server application, it will fall back to its local application.properties file. However, the application will probably fail if all of the properties your application needs are not present there as well, so it's a good practice to copy all properties from your overriding file to the client application.properties file in case fetch fails.
If this didn't fix your problem I would check out this section on property overrides.

Custom file names in Spring Cloud Config Server

How to specify a spring boot application to access only a specific .properties file among other files in my Spring Cloud Config Server.
My Spring Cloud Config has the following files:
application.properties,order-dev.properties,inventory-dev.properties,
all my db and messaging properties are in order-dev and inventory-dev files.
Now I wish to move those properties to orderdb-dev, inventorydb-dev, ordermsg-dev and inventorymsg-dev files.
How do I configure my order and inventory service to pick the property from orderdb-dev, inventorydb-dev, ordermsg-dev and inventorymsg-dev files ? I have been going around to find the property for the same. Read through the official documentation and felt lost. Any help would be appreciated.
Add a bootstrap.yml file under resources folder. Then add the below properties.
spring:
application:
name: order
cloud:
config:
name: ${spring.application.name}, orderdb, ordermsg
profile: dev
This way, it will first load the properties from order-dev.properties file. Then orderdb-dev.properties and then ordermsg-dev.properties.

Spring Cloud Client Config with placeholders

I have a Spring Boot application.yml with this config for Cloud Config:
spring:
cloud:
config:
uri: http://localhost:8080/config
name: ${cluster.name}
profile: ${cluster.idx}
I read cluster.name and cluster.idx from a custom PropertySouce that loads a JSON file. But Spring Boot is not capable of resolve the placeholder yet.
13:04:37,370 ERROR [main] org.springframework.boot.SpringApplication(SpringApplication.java:839) : Application startup failed
java.lang.IllegalArgumentException: Could not resolve placeholder 'cluster.idx' in string value "${cluster.idx}"
How do I tell Spring Boot to load my PropertySource before trying to resolve the placeholders? Thanks in advance.
I'm using Sp Boot 1.4.3 and Sp Cloud Config 1.2.2.
You won't be able to use the property sources as they are not yet available, and will not be at the time that this file is read. You have a couple of options, though. First, you can place these properties into the bootstrap.properties (or bootstrap.yml if you prefer). I suspect that you are trying to do something that's profile driven though and should use the appropriate properties for the profile. In this case, you can create bootstrap-{profile}.yml. So, if you are running with -Dspring.profiles.active=dev, you would have a bootstrap-dev.yml file that would contain the values for this profile.
The second and simpler approach would be to pass these to the VM as arguments. -Dcluster.name=foo -Dcluster.idx=bar

Resources