Can I duplicate a web service for testing? - spring

I have a REST web service exposed at http://server:8080/my-production-ws by JBoss (7). My spring (3.2) configuration has a datasource which points to a my-production-db database. So far so good.
I want to test that web service from the client side, including PUT/POST operations but I obviously don't want my tests to affect the production database.
Is there an easy way to have spring auto-magically create another web service entry point at http://server:8080/my-test-ws or maybe http://server:8080/my-production-ws/test that will have the exact same semantics as the production web service but will use a my-test-db database as a data source instead of my-production-db?
If this is not possible, what is the standard approach to integration testing in that situation?
I'd rather not duplicate every single method in my controllers.

Check the spring Profiles functionality, this should solve the problem. With it its possible to create two datasources with the same bean name in different profiles and then activate only one depending on a parameter passed to the the JVM.

Related

TestContainers - create GenericContainer and get the uri/path

I'am trying to create isolated test env using TestContainers (for database - postgresql and external services - for example authorising service). My question is, how can i set path in application.yml/application.properties to these external services? With db is easy i just need to use "jdbc:tc:postgresql:14.5:///dbtests", to create containers with my services i use GenericContainer<?> and ports are different every start. TestContainers (except db) are initialized in external class.
You always have to think about how you can inject the dynamic connections URLs into your system-under-test. How you can do is very specific to your application. If you create objects yourself, you can simply to construction dependency injection, like in this example.
For frameworks, there is generally a framework-specific approach. As Eddú already mentioned in the comments, Spring-Boot allows the usage of DynamicPropertySource.

Spring Boot: Handle configuration in multitenant application

I am implementing a Spring Boot application which will be providing a multitenant environment. That is achieved in my case by using a database schema for each customer. Example see this project.
Now I am wondering how to implement tenant-specific configurations. I am using #ConfigurationProperties to bundle my property values, but these are getting instantiated once and not for each tenant.
What if I would like to use Spring Cloud Config with multiple tenant specific git repository as an configuration backend. Would it be possible when using a jdbc backend for Spring Cloud Config?
Is there any way with default Spring mechanisms or do I have to implement a database based configuration framework myself?
Edit: For example I have two tenants called Tenant1 and Tenant2. Both are running over the same application in the same context and are writing in the database schemes tenant_1 and tenant_2.
Identification of tenants is happening over keycloak (see Spring Keycloak multi tenant example). So I identify the tenantId from the jwt token and select the database connection like described here.
But now I would need the same mechanism for #Configuration beans. Since #Configuration beans are as far as I know Singletons, so there is always ONE configuration per application scope, and not ONE configuration per tenant.
So using Spring Cloud Config Tenant1 is using https://git-url/tenant1, Tenant2 is using Hashicorp Vault as backend and perhaps Tenant3 will be using a jdbc based configuration backend. And all of that in ONE (of course scalable) application.
In case your application uses tenant specific files (html templates etc), the following can be applied. As I have used the below approach for handling many tenants and works fine and easy to maintain.
I would suggest that you maintain a consistent configuration source (JDBC) for all of your tenant configurations. This helps you have a single source that is cacheable and scalable for your application. Also, you could have your tenants navigate to a configuration page to manage their settings and alter them to suit their needs at any point of time on the fly. (Example Settings: Records Per Page, Theme, Logo, Filters etc...)
Having the tenant configuration in files in git will be a difficult task when you wanted to auto-provision tenant's when they sign-up as it will involve couple of distributed services. Having them in a TenantSettings table with the tenantId as a column could help you get the data in no time and will be easy.
You can use Spring Cloud Config for your scenario and it is adoptable. It is easily configurable and provides out of the box features. For your specific scenario, you can have any number of microservices running yet all controlled by one Spring Cloud Config Server which is connected to one Git Repository. Your all microservices are asking configuration properties from Spring Cloud Config Server and it is directly fetching properties from Git Repository. That repository can have multiple property files. It can hold common properties for all the microservices or specific service based configuration properties. If you want to keep confidential properties more securely, that is also made possible via HashiCorp vault. I will leave an image below for you to get a better idea about this concept.
In the below image, you can see the Git Repository with common configuration property files and specific configuration property files for different services yet in same repository.
I will add another image for you to get a better idea how does this can be arranged with application profiles as well.
Finally I will add something additional to show the power of Spring Cloud Config and out of the box features it allows us to play with. You can automatically refresh configuration properties in running application as well. You can configure Spring Cloud Config to do that. I will add an architectural diagram to achieve that.
References for this answer is taken from Spring in Action, Fifth Edition
Craig Walls

How to run multiple Spring Boot application sharing same context?

I want to run multiple micro-services app sharing same context so that I can run my custom security filter for multiple spring boot(micro-services) app.
Example:
User services : https://ip:port/myapp/user
Product services : https://ip:port/myapp/product
Comment services : https://ip:port/myapp/comment
And I should run a common filter(Custom Security Filter) for all micro-services.
As #luboskrnac suggests - for the security you could simply extract your common logic into a separate JAR.
Regarding your shared application context (I assume you are just referring to the shared URL space, rather than sharing any particular state across the apps etc), then yes - you should use something like Zuul - this can act as a singular interface between external and all your microservices (which, under the hood would all be running in their own unique application context namespace/port number - but Zuul can group those together and expose them with nice URLs on a consistent location).
Luckily the whole Netflix microservice stack is well supported by Spring, so its reasonably straight forward to get up and running with Zuul and Eureka (the discovery service).
I have a hello-world setup of the stack written up here (along with the code): http://automateddeveloper.blogspot.co.uk/2015/09/spring-boot-netflix-oss-adventure-into.html
Extract that filter into separate JAR that will be used by each microservice. That JAR will be separate project versioned and deployed into your artifact repository independently.
In fact in microservice environment, you will have much more "common" beans/functionality that should be shared across services. Therefore such common JAR is necessary in microservice environment.

Is it possible to change properties of a bean (defined for a service) and reload it when the application is running?

I migrated a simple CRUD application developed in Java using OSGi to Grails using Spring. I converted all the REST resources to controllers and HTML pages to GSP views, keeping the rest of the Java code as such.
I have a DBService service, which helps connect to the DB and run queries on it, and a ProcessorService, which uses DBService to perform business operations.
I created beans for these services as follows:
beans = {
dbServiceBean(DBService, "test_db")
processorServiceBean(ProcessorService,ref("dbServiceBean"))
}
Everything is working fine with the above config.
Now, I want the application to be able to process multiple DBs (multi-tenant). I won’t know the name of the DB beforehand, however, so I can’t have a list of dbServiceBeans predefined.
Is it possible to rebuild/reload a bean with dynamically obtained values and reload the dependent beans as well when the application is running?
Grails already have the option to use multiple datasources.
You can change your DBService to get a connection from the datasources configured. If you just change it to a Groovy class and put it in grails-app/service you will get transactions and dependency injection by attribute name for free.

Share spring container between test application and embedded tomcat

We are using cucumber-jvm to write an integration test layer in our application. One of the challenges we are finding is managing the database between the tests and the web application.
A typical scenario is that we want to persist some entities in a Given step of a scenario, then perform some actions on the user interface that may, in turn, persoist more entities. At the end, we want to clean the database. Because the cucumber-jvm tests are in one jvm and the web application is running in another jvm we cannot share a transaction (at least in a way of which I am aware) so the database must be cleaned manually.
My initial thought was to use an Embedded Tomcat server running off of an embedded in-memory database (HSQLDB) in the same JVM as the cucumber-jvm test. This way we might be able to share a single spring container, and by extension a single transaction, from which all objects could be retrieved.
During my initial tests it looks like Spring gets loaded and configured twice: once when the test starts and the cucumber.xml is read, and a second time when the embedded tomcat starts and the web application reads its applicationContext.xml. These appear to be in two completely separate containers because if I try to resolve an object in one container that is specified in the other container then it doesn't resolve. If I duplicate my configuration then I get errors about duplicate beans with the same id.
Is there a way that I can tell Spring to use the same container for both my test application and the embedded tomcat?
I'm using Spring 3.2.2.GA and Embedded Tomcat 7.0.39 (latest versions of both libraries).
Am I crazy? Do I need to provide more technical details? Apologies if I use some incorrect terminology.
Thanks
p.s. If my problem seems familiar to you and you can suggest an alternative solution to the one I am trying, please let me know!
Jeff,
It is normal that spring is loaded twice. There are two places where two spring contexts are created:
In the servlet container listener org.springframework.web.context.ContextLoaderListener that is configured in web.xml. This one reads its configuration from the file set by the context-param contextConfigLocation.
In the implementation of ObjectFactory provided by cucumber-spring plugin cucumber.runtime.java.spring.SpringFactory. This one reads its configuration from cucumber.xml.
The two spring contexts are totally different and their instances are kept in two different places. As a servlet context attribute for the former and kept by the JavaBackend for the latter.
When starting the embedded tomcat, it is possible to get access to the servlet context and thus set ourself the spring context used bt tomcat with the one from cucumber. But, spring has a special class called WebApplicationContext for context used in a servlet container. The cucumber SpringFactory on other hand creates its context through ClassPathXmlApplicationContext. So unless there is a way to specify the type of application context from the xml config, we will have to provide an ObjectFactory that shoots a WebApplicationContext.
What we can do is to have two web.xml. One for the normal and one for the test. For the test, we use our version of the ContexLoader listener.

Resources