Unit testing with Spring and the Jersey Test Framework - spring

I'm writing some JUnit-based integration tests for a RESTful web service using JerseyTest. The JAX-RS resource classes use Spring and I'm currently wiring everything together with a test case like the following code example:
public class HelloResourceTest extends JerseyTest
{
#Override
protected AppDescriptor configure()
{
return new WebAppDescriptor.Builder("com.helloworld")
.contextParam( "contextConfigLocation", "classpath:helloContext.xml")
.servletClass(SpringServlet.class)
.contextListenerClass(ContextLoaderListener.class)
.requestListenerClass(RequestContextListener.class)
.build();
}
#Test
public void test()
{
// test goes here
}
}
This works for wiring the servlet, however, I'd like to be able to share the same context in my test case so that my tests can have access to mock objects, DAOs, etc., which seems to call for SpringJUnit4ClassRunner. Unfortunately, SpringJUnit4ClassRunner creates a separate, parallel application context.
So, anyone know how can I create an application context that is shared between the SpringServlet and my test case?
Thanks!

Override JerseyTest.configure like so:
#Override
protected Application configure() {
ResourceConfig rc = new JerseyConfig();
rc.register(SpringLifecycleListener.class);
rc.register(RequestContextFilter.class);
rc.property("contextConfigLocation", "classpath:helloContext.xml");
return rc;
}
For me the SpringServlet was not required, but if you need that you may be able to call rc.register for that too.

I found a couple of ways to resolve this problem.
First up, over at the geek#riffpie blog there is an excellent description of this problem along with an elegant extension of JerseyTest to solve it:
Unit-testing RESTful Jersey services glued together with Spring
Unfortunately, I'm using a newer version of Spring and/or Jersey (forget which) and couldn't quite get it to work.
In my case, I ended up avoiding the problem by dropping the Jersey Test Framework and using embedded Jetty along with the Jersey Client. This actually made better sense in my situation anyway since I was already using embedded Jetty in my application. yves amsellem has a nice example of unit testing with the Jersey Client and embedded Jetty. For Spring integration, I used a variation of Trimbo's Jersey Tests with Embedded Jetty and Spring

Related

Launch spring boot mvc test from custom testng framework

Where I'm working one of our customer required to use a custom test framework written using testng that allows to handle different parameters and test iterations using excel files.
This framework uses a main class to handle all the tests, lets call it TestManager.
This TestManager defines all the #Before and #After operations and has a method called exec() which is annotated as #Test.
This method is used to call the different components required from the test, these components are java classes that implements a single method exec() containing the logic of the single component.
public class TestManager {
// ... Before, After methods
#Test(
dataProvider = "..."
)
public void exec(Parameter[] inParameter) {
// load parameters...
foreach component:
component.exec()
}
}
public class ComponentXYZ {
public void exec() {
// load input params
// Call a microservice and get results, find value on db, selenium operations...
// unload output params for next components
}
}
This framework was designed to be used with selenium, or to test microservices using some http request library and is contained in a standalone module.
So my project has:
A spring boot module
A test module which (in my idea) should have a dependency over the spring boot module
Given this situation do you think it could be possible to use WebMvcTest to perform integration tests while using this custom framework?
I've been trying for a while but I'm always getting errors or I'm not able to #Autowire MockMvc, I can't seem to start a minimal spring boot instance directly from this test framework...
I don't think running my spring boot app and calling the microservices using http is the correct way to test but at this moment is the only thing it's working.

Combine Jersey with Tyrus

I have a Jersey JAX-RS application which runs on a Grizzly instance:
public class Application {
public static final String BASE_URI = "http://127.0.0.1:8080/rest";
public static void main(String[] args) throws IOException {
ResourceConfig rc = new ResourceConfig().packages("my.package.rest");
HttpServer server = GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc);
System.out.println("Server started, press any key to stop.");
System.in.read();
server.shutdownNow();
}
}
inside my.package.rest there are JAX-RS annotated resources. I'd like to add websocket annotated (#ServerEndpoint, #OnOpen, #OnMessage, etc.) resources using Tyrus on the same server instance (say in "http://127.0.0.1:8080/websocket") but all the documentation I was able to find shows how to start a standalone websocket server using Tyrus + a Grizzly container, not combined with Jersey. I'm looking for something like:
server.getServerConfiguration().addHttpHandler(new SomeTyrusHttpHandler("/websocket"));
but I can't find anything similar to SomeTyrusHttpHandler. How can I combine Jersey and Tyrus in a single Grizzly server?
good question, but there is currently no good answer for this one. You still can do that, but it would require to deep dive into Grizzly internals; Tyrus is registered by an addon (see WebSocketAddOn) and it can be combined with Jersey way of registering into that container.
Please have in mind that integrating these two frameworks together is not trivial challenge - running them in a single container is a first step, but there are other things which need to be taken care of, like "instance provider", lifecycle adjustment, etc. I believe this topic exceeds the scope of one SO answer - you can expect blogpost from me or some other Tyrus/Jersey team member about this. (I'll post it here once that is done).
Anyway, I would recommend to take more conservative approach and use some lightweight container which supports Servlet 3.1; that should require far less work on your side and you'll have standard Servlet runtime / lifecycle.

Shiro with SAML2 in Karaf with JAX-RS (Jersey)

I am creating an application that runs in Karaf as OSGi container, and uses the OSGi HTTP Service and Jersey for exposing REST APIs. I need to add SAML2 authentication and permissions-based authorization. I would like to use the annotation based approach in Shiro for this, as spring seems to be moving away from OSGi. My questions:
Is Shiro with SAML jars a good fit in OSGi environments?
I want to use WSO2 as the identity provider. Are there any caveats of Shiro and WSO2 working together?
For using annotations, the Shiro docs indicate I need to put AspectJ/Spring/Guice jars - Is this still valid in OSGi environments? I would prefer Guice for all my DI needs.
Would be great to have some insights from Shiro users.
UPDATE
I'm using this project: osgi-jax-rs-connector. So, I use Guice-Peaberry to register OSGi services with the interfaces annotated with #Path or #Provider, and the tool takes care of converting them into a REST resource. (Similar to pax-whiteboard?). I was planning to similarly expose my filters as OSGi services, and then dynamically add them along with the resources.
I have had headaches with AspectJ in OSGi in a previous project where I had to switch to vanilla Equinox from Karaf because the equinox weaving hook was not agreeing with Karaf (stack traces from Aries were seen, among other things). So, would doing something like shiro-jersey be better?
I'm sure it is doable, though I already see some restrictions/issues poping up.
for
1) haven't tried it, though you need to make sure that you tell the pax-web and jetty about it, it'll require adding this to the jetty.xml and it might even need to add a fragment bundle to pax-web-jetty so the desired class can be loaded. This will most likely be your first classnotfound issue.
2) don't know of WSO2 so no idea
3) if you want to use annotations, be careful. For Guice you'll mostlikely will need to use Peaberry since afaik Guice isn't "OSGi-fied" yet. Using AspectJ isn't really a good idea in a OSGi environment due to the classloader restrictions. If you have a compile-time weaving it should be fine, but run-time weaving will be a challange.
UPDATE:
Completely forgot about it, but there is a Pax Shiro Project available, maybe this can be a good starting point to get your setup in a correct lineup.
In the interest of readers, I'm sharing the solution I arrived at after some research of existing tools. First, the easy part: Using Shiro annotations in an OSGi environment. I ended up writing the below class since most Shiro-Jersey adapters shared by developers is based on Jersey 1.x.
#Provider
public class ShiroAnnotationResourceFilter implements ContainerRequestFilter {
private static final Map, AuthorizingAnnotationHandler> ANNOTATION_MAP = new HashMap, AuthorizingAnnotationHandler>();
#Context
private ResourceInfo resourceInfo;
public ShiroAnnotationResourceFilter() {
ANNOTATION_MAP.put(RequiresPermissions.class,
new PermissionAnnotationHandler());
ANNOTATION_MAP.put(RequiresRoles.class, new RoleAnnotationHandler());
ANNOTATION_MAP.put(RequiresUser.class, new UserAnnotationHandler());
ANNOTATION_MAP.put(RequiresGuest.class, new GuestAnnotationHandler());
ANNOTATION_MAP.put(RequiresAuthentication.class,
new AuthenticatedAnnotationHandler());
}
public void filter(ContainerRequestContext context) throws IOException {
Class resourceClass = resourceInfo.getResourceClass();
if (resourceClass != null) {
Annotation annotation = fetchAnnotation(resourceClass
.getAnnotations());
if (annotation != null) {
ANNOTATION_MAP.get(annotation.annotationType())
.assertAuthorized(annotation);
}
}
Method method = resourceInfo.getResourceMethod();
if (method != null) {
Annotation annotation = fetchAnnotation(method.getAnnotations());
if (annotation != null) {
ANNOTATION_MAP.get(annotation.annotationType())
.assertAuthorized(annotation);
}
}
}
private static Annotation fetchAnnotation(Annotation[] annotations) {
for (Annotation annotation : annotations) {
if (ANNOTATION_MAP.keySet().contains(annotation.annotationType())) {
return annotation;
}
}
return null;
}
}
The complete project is here.
The above took care of Part 3 of my question.
For Shiro with SAML, I am using the Servicemix wrapped openSAML jar, and it seems to be working okay till now. I did however had to write a bit of code to make Shiro work with SAML2. It's almost on the same lines as shiro-cas, but is a bit more generic to be used with other IdPs. The code is kind of big so sharing a link to the project instead of copying classes to SO. It can be found here.
Now that I have some abstraction between my code and my IdP, WSO2 integration looks a bit simpler.
P.S. Thanks Achim for your comments and suggestions.

How to generate Java client proxy for RESTful service implemented with Spring?

We use Spring to implement REST controller, for example:
#Controller
#RequestMapping("/myservice")
public class MyController {
#RequestMapping(value = "foo", method = RequestMethod.GET)
public #ResponseBody string foo() {...}
}
I can call this service using spring RestTemplate, and it works fine, but I would prefer to invoke it using a proxy, instead of typeless invocation using string url:
// client code:
MyController proxy = getProxy("baseUrl", MyController.class);
String results = proxy.foo();
So the input to proxy generation is java interface with annotations describing REST details.
I read this article and it looks like all types of remote calls do have proxies, and all I need for REST is something like RestProxyFactoryBean, that would take my REST java interface and return type-safe proxy that uses RestTemplate as implementation.
The closest solution I found is JBoss RESTEasy.
But it seems to use different set of annotations, so I am not sure it will work with annotations I already have: #Controller, #RequestMapping.
Are there other options, or RESTEasy is the only one?
Note, I am spring newbie so some obvious spring things are pretty new to me.
Thank you.
Dima
You can try Feign by Netflix, a lightweight proxy-based REST client. It works declaratively through annotations, and it's used by Spring Cloud projects to interact with Netflix Eureka.
One of the reasons the REST paradigm was invented was because expirience with other remoting technologies (RMI, CORBA, SOAP) shows us that often, the proxy-based approach creates more problems than it solves.
Theoretically, a proxy makes the fact that a function call is remote transparent to its users, so they can use the function exactly the same way as if it were a local function call.
In practice however this promise cannot be fulfilled, because remote function calls simply have other properties than local calls. Network outages, congestion, timeouts, load problems to name just a few. If you choose to ignore all these things that can go wrong with remote calls, your code probably won't be very stable.
TL;DR: You probably shouldn't work with a proxy, it's not state of the art any more. Just use RestTemplate.
Here is a project trying to generate runtime proxies from the controller annotations (using RestTemplate in the background to handle proxy calls): spring-rest-proxy-client Very early in implementation though.
This seems to do it: https://swagger.io/swagger-codegen/, and swagger has many other nice things for REST API.
Have a look at https://github.com/ggeorgovassilis/spring-rest-invoker.
All you need is to register FactoryBean:
#Configuration
public class MyConfiguration {
#Bean
SpringRestInvokerProxyFactoryBean BankService() {
SpringRestInvokerProxyFactoryBean proxyFactory = new SpringRestInvokerProxyFactoryBean();
proxyFactory.setBaseUrl("http://localhost/bankservice");
proxyFactory.setRemoteServiceInterfaceClass(BankService.class);
return proxyFactory;
}
and after that you can autowire the interface class:
#Autowired
BookService bookService;
I also ended up making my own library for this. I wanted something that is as small as possible, adds only itself to classpath and no transitive dependencies.
A client is created like:
final StoreApi storeApi = SpringRestTemplateClientBuilder
.create(StoreApi.class)
.setRestTemplate(restTemplate)
.setUrl(this.getMockUrl())
.build();
And rest-requests will be performed when invoking the methods:
storeApi.deleteOrder(1234L);
The is supports both method signatures:
ResponseEntity<X> deleteOrder(Long)
X deleteOrder(Long)

How to test REST in spring app with spring security

I've got spring web application with jersey rest services. However rest is secured via spring security and login process is very hard to perform from unit test code. I'd like to test rest services with whole spring security disabled. Is it even possible?
One of the advantages of annotation based web services is that you can unit-test them easily.
class WebServiceEndpoint {
#Path("/foo/{fooId}")
#POST
#Produces({ MediaType.APPLICATION_XML })
public Response doFoo(#PathParam("fooId") Integer fooId) {
/// ... web service endpoint implementation
}
}
If you're using Spring's servlet filter for security, then there shouldn't be any security-related code in the doFoo method, so you can just create a new WebServiceEndpoint class and call the method. So that's one way of 'disabling' security.
When you say the login process is 'hard', what do you mean? If you've succeeded in logging in once, then you can just reuse the same code in your other unit tests (e.g. in a #Before method).
Just test it as a pojo. Pass in whatever, return whatever, don't load an app context at all - that would be an integration test.
The ability to easily test functionality without the framework loaded is one of the key advantages of spring.
You don't say what's "hard," so I'm assuming that you've got something in your REST service, i.e. in the java method that you want to test, which requires authentication results. Spring has utilities for mocking the authentication results. For example, you can do the following in a #Before setup method:
Object principal = null; // fix this
Object credentials = null; // fix this
Authentication auth = new org.springframework.security.authentication.TestingAuthenticationToken(principal, credentials);
SecurityContextHolder.getContext().setAuthentication(auth);
But again, you haven't said what problem you're actually trying to solve...

Resources