i am trying to make testing with test container from here
there we try to make a container and make springboot connect to it with #DynamicPropertySource.
#Container
private static PostgreSQLContainer container = new PostgreSQLContainer<>("postgres:12.9");
#DynamicPropertySource
public static void overrideProps(DynamicPropertyRegistry registry){
registry.add("jdbc.connectionString", container::getJdbcUrl);
registry.add("jdbc.username", container::getUsername);
registry.add("jdbc.password", container::getPassword);
}
but i am using springboot 2.1.4, there for i can not use #DynamicPropertySource.
is there a way to change the application.property at runtime so it can use port that the container randomly created?
i've tried to change may jdbc.connectionString to jdbc:tc:postgresql:12.9:///databasename but i got error and i don't think that is correct way to do this.
The testcontainers specific JDBC URL should work, but you need to provide one additional property if you use SpringBoot versions before 2.3.0 (as mentioned in the docs):
spring.datasource.url=jdbc:tc:postgresql:12.9:///databasename
spring.datasource.driver-class-name=org.testcontainers.jdbc.ContainerDatabaseDriver
Imho it's the easiest (and recommended) approach.
Alternatively, you can find an example of how to adjust application properties at runtime without #DynamicPropertySource in this spring article:
#SpringBootTest
#Testcontainers
#ContextConfiguration(initializers = ExampleIntegrationTests.Initializer.class)
class ExampleIntegrationTests {
#Container
static Neo4jContainer<?> neo4j = new Neo4jContainer<>();
static class Initializer implements
ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(ConfigurableApplicationContext context) {
TestPropertyValues.of("spring.data.neo4j.uri=" + neo4j.getBoltUrl())
.applyTo(context.getEnvironment());
}
}
}
Related
I'm successfully using Spring Cloud Sleuth in a Spring Boot microservice and am having fields logged and sent over http headers appropriately.
I now need to integrate this same process for logging and header propagation in a Spring Boot command line runner application but it looks like no trace and span are automatically setup since it isn't in the middle of an Http request (as it is a command line app). I cannot see these fields in my logs (with the same %X format in log configuration).
I've looked at the docs and can't find any examples for this specific use case. Is this possible in a command line runner app?
In order to add baggage you need to have a span. Spring Cloud Sleuth and Spring Boot create a span for you when the controller is invoked. If you want to do the same using CLI application, you need to create span yourself.
You have two options.
Using API calls:
Span span = this.tracer.nextSpan().name("mySpan");
// do some work
span.end(); // best to put it in finally to make sure span is always ended
Or you can use annotations:
#NewSpan
public void doWork() {
}
If you use the annotation, please keep in mind the AOP proxies limitations. In particular self invocations (calls using this) would not work.
#SpringBootApplication
public class ConsoleApplication
implements CommandLineRunner {
#Override
public void run(String... args) {
doWork(); //this is the same as this.doWork();
}
#NewSpan
public void doWork() {
}
}
This is not going to work as doWork is not invoked through the AOP proxy. Make sure that you annotate a component managed by Spring and then use an injected instance.
#SpringBootApplication
public class ConsoleApplication
implements CommandLineRunner {
#Autowired
private MyService myService;
#Override
public void run(String... args) {
myService.doWork();
}
}
#Component
class MyService {
#NewSpan
public void doWork() {
}
}
In this case myService is not instance of MyService, but rather an instrumented proxy.
I am trying to retrofit Spring DI into an existing application using Spring Boot. I want to use JSR-330 annotations instead of Spring's. I would like to make prototype scope the default so I don't have to use non-JSR-330 scope #Scope("prototype") everywhere. I first tried to install the JSR330ScopeMetadataResolver using:
SpringApplication application = new SpringApplication(OurApplication.class);
ConfigurableApplicationContext context = application.createContext();
context..setScopeMetadataResolver(new Jsr330ScopeMetadataResolver());
application.run(args);
I still get a singleton when injecting a class with no annotation. I then tried using an ApplicationContextInitializer to do the same thing. Either way, I get a singleton injected. In the debugger, I verified with the initializer that Jsr330ScopeMetadataResolver is getting set in the ApplicationContext. In the Jsr330ScopeMetadataResolver instance, I see a map is getting populated in the default constructor with key /value as singleton. I obviously are missing something. Does anyone know what that is?
We finally were able to figure this out. The solution was:
private static final String CONTEXT_PACKAGES_TO_SCAN =
"my.company.package.*";
public static void main(String[] args) {
SpringApplication application = new SpringApplication(
MainApplication.class);
application.addInitializers(new Jsr330Initializer());
application.run(args);
}
public static class Jsr330Initializer implements
ApplicationContextInitializer<AnnotationConfigApplicationContext>
{
#Override
public void initialize(AnnotationConfigApplicationContext context) {
context.setScopeMetadataResolver(new Jsr330ScopeMetadataResolver());
context.scan(CONTEXT_PACKAGES_TO_SCAN);
}
}
The key is to perform context.scan() in the initializer. Packages to scan must end in ".*", or the main application gets added twice and Spring fails to start.
The annotation #Value("${my.field}") work well if you want to inject data into a non static field. In my case, I'm building test for my spring boot application. I'm using Junit. I have some task to do #BeforeClass and I need some properties from spring application configuration. I'm looking for a elegant way to get my properties.
You can load the properties file in the static setup method on your own and select the values needed in your tests. For some, it might be less convenient than injection with #Value, but it will do the trick.
public class SomeTestClass {
private static String myProperty;
#BeforeClass
public static void setUpClass() throws Exception {
Properties prop = new Properties();
prop.load(new FileInputStream("src/main/resources/application.properties"));
myProperty = prop.getProperty("your.property.key");
}
#Test
public void shouldLoadProperty() throws Exception {
assertEquals("expectedValue", myProperty);
}
}
Spring boot integration test looks like this
#RunWith(SpringRunner.class)
#SpringBootTest(classes = Application)
class IntegrationTest {
static QpidRunner qpidRunner
#BeforeClass
static void init() {
qpidRunner = new QpidRunner()
qpidRunner.start()
}
#AfterClass
static void tearDown() {
qpidRunner.stop()
}
}
So, Qpid instance is run before and teared down after all tests. I want to know is there a way to check whether spring boot application is still running before calling qpidRunner.stop(). I want to stop Qpid only when I'm sure that spring app has finished its stopping.
The Spring Boot integration test can configure an ApplicationListener which listens for ContextClosedEvent. Define a nested #TestConfiguration class inside the test class to add beans to the application's primary configuration.
#TestConfiguration
static class MyConfiguration {
#Bean
public ApplicationListener<ContextClosedEvent> contextClosedEventListener() {
return event -> qpidRunner.stop();
}
}
Taking into account that ConfigurableWebApplicationContext can be injected in a SpringBootTest, adding this lines to the code solved the problem
static ConfigurableWebApplicationContext context
#Autowired
void setContext(ConfigurableWebApplicationContext context) {
AbstractDocsIntegrationTest.context = context
}
#AfterClass
static void tearDown() {
context.stop()
qpidRunner.stop()
}
Spring docs about stop method
Stop this component, typically in a synchronous fashion, such that the
component is fully stopped upon return of this method.
JUnit AfterClass annotated method must be static, therefore #Autowired workaround with setContext method.
I have this class to start up the spring-cloud config server. It is a spring-boot application.
#SpringBootApplication
#EnableConfigServer
#EnableDiscoveryClient
public class ConfigServerApplication {
public static void main( String[] args ) {
SpringApplication.run( ConfigServerApplication.class, args );
}
}
The application runs fine and all my unit tests are fine. However, in our bamboo pipeline, it will initial a sonar process to analyze the code. We keep getting these minor warnings indicating the following:
Utility classes should not have a public constructor
I know that this is a minor issue, but I have been tasked with removing these from our code.
Ideally, you would mark the class final and provide a private constructor, or so all searches provide as a solution. However, a Spring Configuration class cannot be made final and cannot have a private constructor.
Any ideas how to resolve this?
I'm afraid this isn't a problem spring-boot or spring-cloud can solve. You need to add exceptions to your sonar configuration.
Adjusting your sonar settings would be a nicer approach of course, but if you want to please the machine spirits, you can simply add a non-static dummy function to your class, making it "non-utility" in the eyes of the Sonar checker.
It's easy to test:
#RunWith(SpringRunner.class)
#SpringBootTest
public class YourApplicationTest {
#Test
public void shouldLoadApplicationContext() {
}
#Test
public void applicationTest() {
YourApplication.main(new String[] {});
}
}
Now Sonar is saying, this is tested!
(Kudos goes out to: Robert # https://stackoverflow.com/a/41775613/863403)