Writing tests for grizzly sever with jersey with jar dependency - java

I start the server from the terminal via the java -jar target/test-service-1.0-jar-with-dependencies.jar command
However when running tests from Intellij Idea, I just cannot figure out how to start the server..
This is the current code, which doesn't work
private HttpServer server;
private WebTarget target;
#Before
public void setUp() throws Exception {
// start the server
server = Main.startServer();
// create the client
Client c = ClientBuilder.newBuilder().register(JacksonFeature.class).build();
// uncomment the following line if you want to enable
// support for JSON in the client (you also have to uncomment
// dependency on jersey-media-json module in pom.xml and Main.startServer())
// --
// c.configuration().enable(new org.glassfish.jersey.media.json.JsonJaxbFeature());
target = c.target(Main.BASE_URI);
}
This is my startServer code
public static HttpServer startServer() {
// create a resource config that scans for JAX-RS resources and providers
ResourceConfig rc = new ResourceConfig().packages("com.test.service").register(JacksonFeature.class);
EncodingFilter.enableFor(rc, GZipEncoder.class);
rc.register(LoggingFilter.class);
rc.register(MultiPartFeature.class);
rc.register(CORSResponseFilter.class);
// rc.property("config", configParams);
// create and start a new instance of grizzly http server
// exposing the Jersey application at BASE_URI
HttpServer httpServer = GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc);
//httpServer.getServerConfiguration().addHttpHandler(shh);
return httpServer;
}

It should just start by itself. But for testing you probably want to control when it starts. You can pass false as the third argument to the server factory method. That way you control when it should start.
You can call start and stop on the HttpServer instance in your before and after methods in your test. You'll need to update the code in the Main class also, to call start().
You might also want to check out Jersey Test Framework. Here you won't need to start and stop any servers. The framework will handle it for you. It also makes your tests more configurable than your current set up. Say you only want one resource registered or you want to inject some mocks services. Personally, I would go with the test framework.

Related

Register context listener for jersey

I need to perform some clean up steps after shutting down a jersey server. To my mind this could be easily accomplished by implementing a ServletContextListener. The question of course is how to add this listener to the application. I have seen examples where this is done in the file web.xml like this:
<listener>
<listener-class>org.SomeCompany.SomePackage.server.MyListener</listener-class>
</listener>
where the MyListener class looks as follows:
#WebListener
public class MyListener implements ServletContextListener {
The problem is that this approach only works for deployment as a war file. However, I do also ship my software as a standalone jar file which creates a Grizzly web server to deploy the servlet:
HttpServer httpServer = GrizzlyHttpServerFactory.createHttpServer(BASE_URI,
new MyServerConfig());
The class MyServerConfig subclasses from ResourceConfig and uses the various register methods. I would like to add the listener programmatically as well, but calling register doesn't seem to do the job. Any ideas how to fix this?
The first thing you are going to need to configure Grizzly as a servlet container. This is not the default behavior. You are only creating an HTTP Server. So the first thing you will need to is Grizzly servlet dependency
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-grizzly2-servlet</artifactId>
<version>${jersey2.version}</version>
</dependency>
So here's the deal with this. With this artifact, instead of the Grizzly HttpServer with GrizzlyHttpServerFactory, you would instead use the GrizzlyWebContainerFactory. The only thing is, if you look though the factory API methods, there really isn't a place to register any listeners, and from what I tested, the #WebListener annotation will not automatically get picked up. What we need access to is the Grizzly WebAppContext that Jersey uses to create the Grizzly servlet container.
The way I was able to get it to work, was just to grab some code from the GrizzlyWebContainerFactory.create source code, and just create the container myself. It's really not much code. Most of the source code does checks as it needs to be universal. But in a single use case (with no init-params), you can pretty much cut the code down to this
private static HttpServer create(URI u, Servlet servlet) throws IOException {
String path = u.getPath();
path = String.format("/%s", UriComponent.decodePath(u.getPath(), true)
.get(1).toString());
WebappContext context = new WebappContext("GrizzlyContext", path);
context.addListener(MyListener.class);
ServletRegistration registration;
registration = context.addServlet(servlet.getClass().getName(), servlet);
registration.addMapping("/*");
HttpServer server = GrizzlyHttpServerFactory.createHttpServer(u);
context.deploy(server);
return server;
}
Then just call HttpServer server = create(BASE_URI, new ServletContainer(resourceConfig));
As an aside, for your use case (I just re-read the question :-), Jersey also has Event Listeners. You can write an ApplicationEventListener and listen for the destroy event, and do all your processing there.

Running Verticle from start() method

I'm new to Vert.x and I'm a little bit confused with how to run\deploy Vert.x app.
I'm used to write a server by having a main class with static main() method which there performs all my initial startup code, like: connecting to DB, reading configuration files, initializing internal services and eventually creating the listening socket for accepting new connections.
For example:
public class Server {
public static void main(String args[]) {
Server server = new Server();
server.run();
}
public void run() {
// load configuration
....
// Connect to DB
....
// Initialize internal services
....
// Create listening socket on server port
...
// and more...
}
now to my question:
Vert.x forces me to make my main class extends Verticle class and override start() method
to initialize the listening socket.
so now all my initialization process must be done inside this start() method.
Does this make sense??
and I can never run my application via command line like I'm used to but rather use the "vertex" app
Am I missing something??
Yes, you are correct. A vertx app is nothing but a set of verticles running inside vertx instances.
If you want your app to have main method as usual then you can use vertx as embedded mode i.e inside your main method you start a vertx instance using the API and then start verticles inside that instance.
Check out embedding guide at: https://vertx.io/vertx2/embedding_manual.html

Unit testing FTP consumer with Apache Camel

I have the below route. In unit test, since I doesn't have the FTP server available, I'd like to use camel's test support and send an invalid message to "ftp://hostname/input" and verify that it failed and routed to "ftp://hostname/error".
I gone through the documentation which mainly talks about using the "mock:" endpoint but I am not sure how to use it in this scenario.
public class MyRoute extends RouteBuilder
{
#Override
public void configure()
{
onException(EdiOrderParsingException.class).handled(true).to("ftp://hostname/error");
from("ftp://hostname/input")
.bean(new OrderEdiTocXml())
.convertBodyTo(String.class)
.convertBodyTo(Document.class)
.choice()
.when(xpath("/cXML/Response/Status/#text='OK'"))
.to("ftp://hostname/valid").otherwise()
.to("ftp://hostname/invalid");
}
}
As Ben says you can either setup a FTP server and use the real components. The FTP server can be embedded, or you can setup a FTP server in-house. The latter is more like an integration testing, where you may have a dedicated test environment.
Camel is very flexible in its test kit, and if you want to build an unit test that do not use the real FTP component, then you can replace that before the test. For example in your example you can replace the input endpoint of a route to a direct endpoint to make it easier to send a message to the route. Then you can use an interceptor to intercept the sending to the ftp endpoints, and detour the message.
The advice with part of the test kit offers these capabilities: http://camel.apache.org/advicewith.html. And is also discussed in chapter 6 of the Camel in action book, such as section 6.3, that talks about simulating errors.
In your example you could do something a like
public void testSendError() throws Exception {
// first advice the route to replace the input, and catch sending to FTP servers
context.getRouteDefinitions().get(0).adviceWith(context, new AdviceWithRouteBuilder() {
#Override
public void configure() throws Exception {
replaceFromWith("direct:input");
// intercept valid messages
interceptSendToEndpoint("ftp://hostname/valid")
.skipSendToOriginalEndpoint()
.to("mock:valid");
// intercept invalid messages
interceptSendToEndpoint("ftp://hostname/invalid")
.skipSendToOriginalEndpoint()
.to("mock:invalid");
}
});
// we must manually start when we are done with all the advice with
context.start();
// setup expectations on the mocks
getMockEndpoint("mock:invalid").expectedMessageCount(1);
getMockEndpoint("mock:valid").expectedMessageCount(0);
// send the invalid message to the route
template.sendBody("direct:input", "Some invalid content here");
// assert that the test was okay
assertMockEndpointsSatisfied();
}
From Camel 2.10 onwards we will make the intercept and mock a bit easier when using advice with. As well we are introducing a stub component. http://camel.apache.org/stub
Have a look at MockFtPServer!
<dependency>
<groupId>org.mockftpserver</groupId>
<artifactId>MockFtpServer</artifactId>
<version>2.2</version>
<scope>test</scope>
</dependency>
With this one you can simulate all sorts of behaviors like permission problems, etc:
Example:
fakeFtpServer = new FakeFtpServer();
fakeFtpServer.setServerControlPort(FTPPORT);
FileSystem fileSystem = new UnixFakeFileSystem();
fileSystem.add(new DirectoryEntry(FTPDIRECTORY));
fakeFtpServer.setFileSystem(fileSystem);
fakeFtpServer.addUserAccount(new UserAccount(USERNAME, PASSWORD, FTPDIRECTORY));
...
assertTrue("Expected file to be transferred", fakeFtpServer.getFileSystem().exists(FTPDIRECTORY + "/" + FILENAME));
take a look at this unit test and those in the same directory...they'll show you how to standup a local FTP server for testing and how to use CamelTestSupport to validate scenarios against it, etc...
example unit test...
https://svn.apache.org/repos/asf/camel/trunk/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FromFileToFtpTest.java
which extends this test support class...
https://svn.apache.org/repos/asf/camel/trunk/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpsServerTestSupport.java
In our project we do not create mock FTP Server to test the route but we use properties that can be replaced by a file Camel Component for the local development and unit testing.
Your code would look like this:
public class MyRoute extends RouteBuilder
{
#Override
public void configure()
{
onException(EdiOrderParsingException.class)
.handled(true)
.to("{{myroute.error}}");
from("{{myroute.input.endpoint}}")
.bean(new OrderEdiTocXml())
.convertBodyTo(String.class)
.convertBodyTo(Document.class)
.choice()
.when(xpath("/cXML/Response/Status/#text='OK'"))
.to("{{myroute.valid.endpoint}}}")
.otherwise()
.to("{{myroute.invalid.endpoint}}");
}
}
And locally and for system test we use a file endpoint declared in the property file:
myroute.input.endpoint=file:/home/user/myproject/input
myroute.valid.endpoint=file:/home/user/myproject/valid
myroute.invalid.endpoint=file:/home/user/myproject/invalid
myroute.error=file:/home/user/myproject/error
or in a JUnit CamelTestSupport you can use the useOverridePropertiesWithPropertiesComponent method to set the properties you want to overrides.
As an alternative you can also use a "direct" route instead but you can miss some File options that can be tested by the unit test.
And we only test the FTP connection with the real system by setting the properties like this:
myroute.input.endpoint=ftp://hostname/input
myroute.valid.endpoint=ftp://hostname/valid
myroute.invalid.endpoint=ftp://hostname/invalid
myroute.error=ftp://hostname/error
With this you can also have different configuration for e.g production server that will differentiate from the Integration Test Environment.
Example of Properties for Production environment:
myroute.input.endpoint=ftp://hostname-prod/input
myroute.valid.endpoint=ftp://hostname-prod/valid
myroute.invalid.endpoint=ftp://hostname-prod/invalid
myroute.error=ftp://hostname-prod/error
In my opinion it is totally acceptable to use file endpoint to simplify the JUnit code and it will test the route only and not the connection.
Testing the connection is more like an Integration Test and should be executed on the real server connected with the real external system (in your case FTP servers, but can be other endpoints/systems as well).
By using properties you can also configure different URL's per environment (For example: we have 3 testing environments and one production environment, all with different endpoints).

Simplest remoting server using Spring HttpInvoker

For (JUnit) testing purposes I'd like to make a simple application that would be the server to be invoked using Spring HttpInvoker. I don't want to make a real webapp to be deployed in any servlet container, only something standalone.
Do you have any ideas how to make it as simply as possible? (Solutions without embedded Tomcat or stuff are preferred..)
This will work out well for you - http://docs.codehaus.org/display/JETTY/ServletTester
#BeforeClass
public static void initServletContainer() throws Exception {
tester = new ServletTester();
tester.setContextPath("/");
tester.addServlet(DummyServlet.class, "/dummy");
baseUrl = tester.createSocketConnector(true);
tester.start();
System.out.println(baseUrl);
}
You can start up the server in your #BeforeClass method, record the baseUrl where the server starts up and use this url to test your client.
http://code.google.com/p/jianwikis/wiki/SpringHttpRemotingWithEmbeddedJettyServer

Java - Create a web service from an available class

I had a java project and after lots of research I managed to convert it to a Dynamic Web Project in Eclipse. Now I want to add a new Web Service to it. I have already developed a class. I want to convert it to a standard Web service so I can call it from my silverlight application. Here's my current class:
public class MyWebService
{
#Resource
WebServiceContext context;
#WebMethod
public String ProcessQuery(#WebParam(name="query") String q)
{
MessageContext messageContext = context.getMessageContext();
HttpServletRequest request = (HttpServletRequest) messageContext.get(SOAPMessageContext.SERVLET_REQUEST);
// now you can get anything you want from the request
}
public static void main(String[] args) throws Exception
{
String address = "http://127.0.0.1:8023/_WebServiceDemo";
Endpoint.publish(address, new MyWebService());
new DocumentServer();
System.out.println("Listening: " + address);
}
}
How can I do it in Eclipse? Please post a link to a tutorial or a quick step by step guide. I'm a .Net developer and I'm very new to Java.
Thank you.
PS: So basically I want to publish this service in a standard way rather than calling this main function and using Endpoint.publish() method.
The Eclipse wiki has a tutorial using the Web Tools Platform to do just what you are looking for. It requires WTP and Tomcat, if you don't have those already available to Eclipse. It starts with an unannotated class and finishes with a WSDL and test client. It allows you to view generated SOAP messages.
To create, it instructs you to select the file you want to convert into a web service and run File -> New -> Other... -> Web Services -> Web Service. Then you click Next, move the slider to the Start Service position, and client to Test Client. You select Monitor the Web Service and then click Finish. Then you can play with your Test Client and see your generated WSDL.
Note that the above paragraph is a summary of the tutorial, which you can find in full at the provided link.

Categories