I am unable to import #WithAnonymousUser annotaion in Junit 4. It is showing error in both corresponding import statement
import org.springframework.security.test.context.support.WithAnonymousUser;
and annotation
#WithAnonymousUser
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.security.test.context.support.WithAnonymousUser;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:**/dispatcher-servlet.xml"})
public class SecurityUtilsTest {
Authentication authentication;
public void setup() {
authentication = Mockito.mock(Authentication.class);
SecurityContext securityContext = Mockito.mock(SecurityContext.class);
Mockito.when(securityContext.getAuthentication()).thenReturn(authentication);
SecurityContextHolder.setContext(securityContext);
}
#Test
#WithAnonymousUser
public void testIsAuthenticated_Failure() {
boolean result = SecurityUtils.isAuthenticated();
assertFalse(result);
}
Thanks in advance.
You need to include the Spring Security Test jar in your project. How you do this depends on how you are building your project.
If you are using maven, add this to your pom.xml:
<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-test -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<version>5.0.5.RELEASE</version>
<scope>test</scope>
</dependency>
Related
I need to install the RediSearch module on top of a GCP memorystore redis instance.
I followed the steps:
docker run -p 6379:6379 redislabs/redisearch:latest
I pushed this docker image to a Kubernetes cluster and exposed the external IP. I used that external IP and the 6379 port as configuration for my application but I'm not able to connect to RediSearch.
code:
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.beam.sdk.Pipeline;
import org.apache.beam.sdk.PipelineResult;
import org.apache.beam.sdk.options.Default;
import org.apache.beam.sdk.options.Description;
import org.apache.beam.sdk.options.PipelineOptions;
import org.apache.beam.sdk.options.PipelineOptionsFactory;
import org.apache.beam.sdk.transforms.Create;
import org.apache.beam.sdk.transforms.DoFn;
import org.apache.beam.sdk.transforms.ParDo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.redisearch.client.Client;
import io.redisearch.*;
public class RediSearch {
static Client client = new Client("testdoc1", "clusteripaddress", 8097);
private static final Logger LOG = LoggerFactory.getLogger(RediSearch.class);
public interface Options extends PipelineOptions {
#Description("gcp project id.")
#Default.String("XXXX")
String getProjectId();
void setProjectId(String projectId);
}
public static PipelineResult run(Options options) throws IOException {
Pipeline pipeline = Pipeline.create(options);
pipeline.apply(Create.of("test"))
.apply(ParDo.of(new DoFn<String, String>() {
private static final long serialVersionUID = 1L;
#ProcessElement
public void processElement(ProcessContext c) throws Exception {
String pubsubmsg = c.element();
Schema sc = new Schema()
.addTextField("title", 5.0)
.addTextField("body", 1.0)
.addNumericField("price");
client.createIndex(sc, Client.IndexOptions.Default());
Map<String, Object> fields = new HashMap<String, Object>();
fields.put("title", "hello world");
fields.put("body", "lorem ipsum");
fields.put("price", 800);
fields.put("price", 1337);
fields.put("price", 2000);
client.addDocument("searchdoc3", fields);
SearchResult[] res = client.searchBatch(new Query("hello world").limit(0, 5).setWithScores());
for (Document d : res[0].docs) {
LOG.info("redisearchlog{}",d.getId().startsWith("search"));
LOG.info("redisearchlog1{}",d.getProperties());
LOG.info("redisearchlog2{}",d.toString());
}
}
}));
return pipeline.run();
}
public static void main(String[] args) throws IOException {
Options options = PipelineOptionsFactory.fromArgs(args).as(Options.class);
run(options);
}
}
Error :
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
at redis.clients.jedis.util.Pool.getResource(Pool.java:59)
at redis.clients.jedis.JedisPool.getResource(JedisPool.java:234)
at redis.clients.jedis.JedisPool.getResource(JedisPool.java:15)
at io.redisearch.client.Client._conn(Client.java:137)
at io.redisearch.client.Client.getAllConfig(Client.java:275)
at com.testing.redisearch.RediSearch$1.processElement(RediSearch.java:59)
Caused by: redis.clients.jedis.exceptions.JedisConnectionException: Failed connecting to host xxxxxxxxxxx:6379
at redis.clients.jedis.Connection.connect(Connection.java:204)
at redis.clients.jedis.BinaryClient.connect(BinaryClient.java:100)
at redis.clients.jedis.BinaryJedis.connect(BinaryJedis.java:1894)
at redis.clients.jedis.JedisFactory.makeObject(JedisFactory.java:117)
at org.apache.commons.pool2.impl.GenericObjectPool.create(GenericObjectPool.java:889)
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:424)
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:349)
at redis.clients.jedis.util.Pool.getResource(Pool.java:50)
at redis.clients.jedis.JedisPool.getResource(JedisPool.java:234)
at redis.clients.jedis.JedisPool.getResource(JedisPool.java:15)
at io.redisearch.client.Client._conn(Client.java:137)
at io.redisearch.client.Client.getAllConfig(Client.java:275)
at com.testing.redisearch.RediSearch$1.processElement(RediSearch.java:59)
at com.testing.redisearch.RediSearch$1$DoFnInvoker.invokeProcessElement(Unknown Source)
at org.apache.beam.runners.dataflow.worker.repackaged.org.apache.beam.runners.core.SimpleDoFnRunner.invokeProcessElement(SimpleDoFnRunner.java:218)
at org.apache.beam.runners.dataflow.worker.repackaged.org.apache.beam.runners.core.SimpleDoFnRunner.processElement(SimpleDoFnRunner.java:183)
at org.apache.beam.runners.dataflow.worker.SimpleParDoFn.processElement(SimpleParDoFn.java:335)
at org.apache.beam.runners.dataflow.worker.util.common.worker.ParDoOperation.process(ParDoOperation.java:44)
at org.apache.beam.runners.dataflow.worker.util.common.worker.OutputReceiver.process(OutputReceiver.java:49)
at org.apache.beam.runners.dataflow.worker.util.common.worker.ReadOperation.runReadLoop(ReadOperation.java:201)
at org.apache.beam.runners.dataflow.worker.util.common.worker.ReadOperation.start(ReadOperation.java:159)
at org.apache.beam.runners.dataflow.worker.util.common.worker.MapTaskExecutor.execute(MapTaskExecutor.java:77)
at org.apache.beam.runners.dataflow.worker.BatchDataflowWorker.executeWork(BatchDataflowWorker.java:411)
at org.apache.beam.runners.dataflow.worker.BatchDataflowWorker.doWork(BatchDataflowWorker.java:380)
at org.apache.beam.runners.dataflow.worker.BatchDataflowWorker.getAndPerformWork(BatchDataflowWorker.java:305)
at org.apache.beam.runners.dataflow.worker.DataflowBatchWorkerHarness$WorkerThread.doWork(DataflowBatchWorkerHarness.java:140)
at org.apache.beam.runners.dataflow.worker.DataflowBatchWorkerHarness$WorkerThread.call(DataflowBatchWorkerHarness.java:120)
at org.apache.beam.runners.dataflow.worker.DataflowBatchWorkerHarness$WorkerThread.call(DataflowBatchWorkerHarness.java:107)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.net.SocketTimeoutException: connect timed out
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at redis.clients.jedis.Connection.connect(Connection.java:181)
... 31 more
Any solution is appreciated.
There are multiple causes as per the error JedisConnectionException: Could not get a resource from the pool. According to the answers in this question the problem is that the connection to RediSearch couldn't be established, be it because Redis is not running, the connection times out or it cannot be allocated.
Regardless, I have noticed that even though you deploy Redis on port 6379, in your code you are trying to access it on port 8097. Please change your Client declaration to the following and retry the connection.
static Client client = new Client("testdoc1", "<cluster_ip_address>", 6379);
If you are looking to have the RediSearch module in your memorystore instance, it appears that may not be supported yet. You can see in the google cloud docs here that at the time of writing this, even for version 5.0, redis modules are not supported.
Dependencies:
RestLet 2.3
Jetty 9.4
MyServer.Java
import org.apache.log4j.Logger;
import org.apache.log4j.xml.DOMConfigurator;
import org.restlet.Component;
import org.restlet.Server;
import org.restlet.data.Protocol;
public class MyServer {
public static void main(String[] a) {
Component component = new Component();
Server server = component.getServers().add(Protocol.HTTP, 5000);
server.getContext().getParameters().add("useForwardedForHeader", "true");
component.getDefaultHost().attach(new MyApplication());
try {
System.out.println("Going to start MyServer");
component.start();
System.out.println("Server started on port " + port);
} catch (Exception e) {
log.error(e, e);
}
}
}
MyApplication.java
import com.myApp.resources.*;
import org.restlet.Application;
import org.restlet.Restlet;
import org.restlet.routing.Router;
public class MyApplication extends Application {
#Override
public Restlet createInboundRoot() {
Router router = new Router(getContext());
router.attach("/App", MyResource.class);
return router;
}
}
MyResource.Java
import org.restlet.resource.ServerResource;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.Date;
#Path("/getDetails")
public class MyResource extends ServerResource{
#GET
#Path("/{number}")
public Object getData(#PathParam("number") String number) {
try {
System.out.println("number: " + number);
} catch (Exception e) {
e.printStackTrace();
}
Response.ResponseBuilder builder = Response.ok("Received", MediaType.TEXT_PLAIN);
return builder.build();
}
Now I'm starting my application it starting with the following console log...
Going to start MyServer
[main] INFO org.eclipse.jetty.util.log - Logging initialized #291ms to org.eclipse.jetty.util.log.Slf4jLog
[main] WARN org.eclipse.jetty.server.AbstractConnector - Ignoring deprecated socket close linger time
Starting the Jetty [HTTP/1.1] server on port 5000
[main] INFO org.eclipse.jetty.server.Server - jetty-9.4.14.v20181114; built: 2018-11-14T21:20:31.478Z; git: c4550056e785fb5665914545889f21dc136ad9e6; jvm 1.8.0_181-b13
[main] INFO org.eclipse.jetty.server.AbstractConnector - Started ServerConnector#3327bd23{HTTP/1.1,[http/1.1]}{0.0.0.0:5001}
[main] INFO org.eclipse.jetty.server.Server - Started #446ms
Starting com.myApp.server.MyApplication application
Server started on port 5000
Now when I'm trying to get the result by using localhost:5000/App/getDetails/5426. I'm unable to get the response.
Even I'm getting following message on the console...
[qtp586617651-20] WARN org.eclipse.jetty.server.HttpChannel - /App/getDetails/GJ0125 java.io.IOException: Restlet exception
Any help would be appreciated. Also if any other way to implement then let me know.
I have a Java EE server/client architecture which communicate with each other by using SSL connection. When the connection is made, the client can interrogate the server web services. My question is how can I access to client certificate information in the server web service ? My server controller below :
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
#Path("mycontroller")
#Consumes(MediaType.APPLICATION_XML)
#Produces(MediaType.APPLICATION_XML)
public class Controller {
#GET
#Path("dosomething")
public Response doSomething() {
// How can I have access to certificate information here ?
return Response.ok().build();
}
}
I found a way to do what I wanted.
First, the server has to be configurated to require client certificate authentication. In my case I use a JBoss server and had to add this in the standalone.xml file :
...
<subsystem xmlns="urn:jboss:domain:web:1.1" default-virtual-server="default-host" native="false">
...
<connector name="https" protocol="HTTP/1.1" scheme="https" socket-binding="https" enable-lookups="false" secure="true">
<ssl name="localhost" key-alias="localhost" password="server" certificate-file="${jboss.server.config.dir}/server.jks" certificate-key-file="${jboss.server.config.dir}/server.jks" ca-certificate-file="${jboss.server.config.dir}/truststore.jks" protocol="TLSv1" verify-client="true" />
</connector>
...
</subsystem>
...
And then in my controller I had to inject HttpServletRequest and finally I could obtain an instance of X509Certificate which contains the certificate information :
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.servlet.http.HttpServletRequest;
import java.security.cert.X509Certificate;
#Path("mycontroller")
#Consumes(MediaType.APPLICATION_XML)
#Produces(MediaType.APPLICATION_XML)
public class Controller {
#Context
private HttpServletRequest request;
#GET
#Path("dosomething")
public Response doSomething() {
X509Certificate[] certChain = (X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate");
X509Certificate certificate = certChain[0];
return Response.ok().build();
}
}
If you are looking for the standard certificate information that would be found in the HTTP Headers and the HTTP Servlet Reqeust object, such as Client certificate information from Apache HTTP reverse proxy. You can inject these
For Example:
#Context private HttpServletRequest servletRequest;
#Context private HttpServletContext servletContext;
( see Get HttpServletRequest in Jax Rs / Appfuse application? or in the Java EE tutorial )
If you wish to access the keystore file and load the private key of the certificate, then file access should be done through a JNDI file resource or a JCA adaptor.
But i would advise caution, the application server should handle all the SSL/TLS connection security your WAR component just declares that it wants the connection to be "confidential" in the web.xml file. Mixing the message level security and authentication with the applicaition or transport protocol security can break separation of concerns. i.e. keeping authentication attached to the message in a bus or hub scenario.
I am trying to write a unit test for a Mule flow that uses the Quartz connector. However, I receive the following XML error stating that Mule doesn't know how to parse the "quartz-connector" tag when running the unit test. However, quartz-2.0.2.jar and quartz-1.8.5.jar are both in my classpath, and as you can see below, I have added quartz as part of the XML namespace and the XSD to to the root tag. I have searched on many forums, including this one, but I can't find the solution to my error. Please tell me what I am doing incorrectly. I am using Mule Studio 3.5.0 and JDK 1.7 to run this unit test.
Error
org.mule.api.config.ConfigurationException: Line 9 in XML document from URL [file:/C:/Users/smith/Development/MuleStudio_Workspace/funnel-mule-app/funnel-mule-app-batch/funnel-mule-app-batch-int/src/main/app/log_cleanup.xml] is invalid; nested exception is org.xml.sax.SAXParseException; lineNumber: 9; columnNumber: 89; cvc-complex-type.2.4.a: Invalid content was found starting with element 'quartz:connector'. One of '{"http://www.mulesoft.org/schema/mule/core":annotations, "http://www.mulesoft.org/schema/mule/core":description, "http://www.springframework.org/schema/beans":beans, "http://www.springframework.org/schema/beans":bean, "http://www.springframework.org/schema/context":property-placeholder, "http://www.springframework.org/schema/beans":ref, "http://www.mulesoft.org/schema/mule/core":global-property, "http://www.mulesoft.org/schema/mule/core":configuration, "http://www.mulesoft.org/schema/mule/core":notifications, "http://www.mulesoft.org/schema/mule/core":abstract-extension, "http://www.mulesoft.org/schema/mule/core":abstract-mixed-content-extension, "http://www.mulesoft.org/schema/mule/core":abstract-agent, "http://www.mulesoft.org/schema/mule/core":abstract-security-manager, "http://www.mulesoft.org/schema/mule/core":abstract-transaction-manager, "http://www.mulesoft.org/schema/mule/core":abstract-connector, "http://www.mulesoft.org/schema/mule/core":abstract-global-endpoint, "http://www.mulesoft.org/schema/mule/core":abstract-exception-strategy, "http://www.mulesoft.org/schema/mule/core":abstract-flow-construct, "http://www.mulesoft.org/schema/mule/core":flow, "http://www.mulesoft.org/schema/mule/core":sub-flow, "http://www.mulesoft.org/schema/mule/core":abstract-model, "http://www.mulesoft.org/schema/mule/core":abstract-interceptor-stack, "http://www.mulesoft.org/schema/mule/core":abstract-filter, "http://www.mulesoft.org/schema/mule/core":abstract-transformer, "http://www.mulesoft.org/schema/mule/core":processor-chain, "http://www.mulesoft.org/schema/mule/core":custom-processor, "http://www.mulesoft.org/schema/mule/core":invoke, "http://www.mulesoft.org/schema/mule/core":abstract-global-intercepting-message-processor, "http://www.mulesoft.org/schema/mule/core":custom-queue-store, "http://www.mulesoft.org/schema/mule/core":abstract-processing-strategy}' is expected. (org.mule.api.lifecycle.InitialisationException)
at org.mule.config.builders.AbstractConfigurationBuilder.configure(AbstractConfigurationBuilder.java:52)
at org.mule.config.builders.AbstractResourceConfigurationBuilder.configure(AbstractResourceConfigurationBuilder.java:78)
at org.mule.context.DefaultMuleContextFactory.createMuleContext(DefaultMuleContextFactory.java:84)
at org.mule.tck.junit4.AbstractMuleContextTestCase.createMuleContext(AbstractMuleContextTestCase.java:203)
at org.mule.tck.junit4.AbstractMuleContextTestCase.setUpMuleContext(AbstractMuleContextTestCase.java:133)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:27)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
at org.junit.rules.TestWatcher$1.evaluate(TestWatcher.java:46)
at org.junit.internal.runners.statements.FailOnTimeout$1.run(FailOnTimeout.java:28)
Mule Flow
<mule xmlns:tracking="http://www.mulesoft.org/schema/mule/ee/tracking" xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:quartz="http://www.mulesoft.org/schema/mule/quartz" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation" xmlns:spring="http://www.springframework.org/schema/beans" xmlns:core="http://www.mulesoft.org/schema/mule/core" version="EE-3.4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
http://www.mulesoft.org/schema/mule/quartz http://www.mulesoft.org/schema/mule/quartz/current/mule-quartz.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd
http://www.mulesoft.org/schema/mule/ee/tracking http://www.mulesoft.org/schema/mule/ee/tracking/current/mule-tracking-ee.xsd">
<quartz:connector name="TimeToStart2" validateConnections="true" doc:name="Quartz"/>
<flow name="cleanup_flow" doc:name="cleanup_flow">
<quartz:inbound-endpoint name="LogCleanUpStart" jobName="LogCleanUp" cronExpression="${log.cleanup.cron.start}" repeatInterval="0" responseTimeout="10000" connector-ref="TimeToStart2" doc:name="Scheduler">
<quartz:event-generator-job/>
</quartz:inbound-endpoint>
<set-variable variableName="#['failCounter']" value="#[0]" doc:name="Init Fail Counter"/>
<logger message="Log Cleanup Started" level="INFO" doc:name="StartLogger"/>
<flow-ref name="cleanup_for_loop_body" doc:name="cleanup_for_loop_body_ref"/>
</flow>
</mule>
Mule Unit Test
import static com.jayway.restassured.RestAssured.expect;
import static com.xebialabs.restito.builder.stub.StubHttp.whenHttp;
import static com.xebialabs.restito.builder.verify.VerifyHttp.verifyHttp;
import static com.xebialabs.restito.semantics.Action.status;
import static com.xebialabs.restito.semantics.Action.stringContent;
import static com.xebialabs.restito.semantics.Condition.method;
import static com.xebialabs.restito.semantics.Condition.post;
import static com.xebialabs.restito.semantics.Condition.delete;
import static com.xebialabs.restito.semantics.Condition.uri;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import org.glassfish.grizzly.http.Method;
import org.glassfish.grizzly.http.util.HttpStatus;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.Ignore;
import org.mule.api.MuleMessage;
import org.mule.api.client.MuleClient;
import org.mule.tck.junit4.FunctionalTestCase;
import com.xebialabs.restito.server.StubServer;
public class LogCleanupTest extends FunctionalTestCase
{
private StubServer server;
#Before
public void start()
{
server = new StubServer().run();
}
#After
public void stop()
{
server.stop();
}
#Override
/**
* Return the list of flow names that will be tested
*/
protected String getConfigResources()
{
String flowNames = "src/main/app/log_cleanup.xml, src/test/resources/batch_global_test_config_internal.xml";
return flowNames;
}
/**
* Make sure that a successful cleanup response does not increment the retry counter.
*/
#Test
public void testLCSuccessResponse() throws Exception
{
MuleClient client = muleContext.getClient();
String logURL = "/api/log/cleanup/XYZ/";
//When a Delete request is made to this Log URL, return an OK response.
whenHttp(server).match(delete(logURL)).then(stringContent("String response"), status(HttpStatus.OK_200));
}
}
There are JAR dependencies missing.
Instead of adding the JARs by hand, you'd rather use Maven to bring the Mule Quartz Transport JAR into your project, which will bring all its needed dependencies. Just make sure to scope the transport as provided.
I am trying to set up some unit tests with the Play framework. A lot of my logic is built into scheduled akka actors that go off and gather data in the background. My problem is that I can't figure out how to unit test them. I literally have no clue how to approach it. I'm trying to use akka-testkit, but I'm basically flailing around. Does anyone have any suggestions on how to even approach it? Examples would be incredibly useful. This is an example of the abomination I am currently working with:
package test
import org.specs2.mutable._
import controllers.Scanner
import java.util.UUID
import org.joda.time.DateTime
import akka.testkit.TestActorRef
import play.api.Logger
import play.api.test.{FakeApplication, TestServer}
import models.PSqlEnum
class ScannerTest extends Specification {
val appId = UUID.randomUUID()
val app = models.App(appId, "TestApp", "TestServer", "TestComponent", "Test Description", DateTime.now(),
DateTime.now(), true, 3, 60, PSqlEnum("scanType", "mandatory"), "http://localhost")
val rules = <Rule name="DivisionDataIsAvailable" elementsToCheck="DivisionDataIsAvailable"
ruleType="is, true, yellow" />
<Rule name="DivisionDataLoadIsHealthy" elementsToCheck="DivisionDataLoadIsHealthy"
ruleType="is, true, red" />;
"Scanner" should {
"test something" in {
val fakeApp = TestServer(3333)
fakeApp.start()
implicit val actorSystem = play.api.libs.concurrent.Akka.system(fakeApp.application)
val scanner = TestActorRef(new Scanner(app, rules)).underlyingActor
Logger.warn(scanner.getResponseFromWebService.toString)
fakeApp.stop()
1 === 1
}
}
}
This is obviously not really testing anything. I am basically trying to get it to get through to the 1 === 1 at this point just to see if I can get the runtime errors to stop. The errors this code is generating are these:
INFO - Starting application default Akka system.
[info] ScannerTest
[info] Scanner should
[info] ! test something
[error] ThrowableException: akka.actor.LocalActorRef.<init>(Lakka/actor/ActorSystemImpl;Lakka/actor/Props;Lakka/actor/InternalActorRef;Lakka/actor/ActorPath;)V (TestActorRef.scala:21)
[error] akka.testkit.TestActorRef.<init>(TestActorRef.scala:21)
[error] akka.testkit.TestActorRef$.apply(TestActorRef.scala:135)
[error] akka.testkit.TestActorRef$.apply(TestActorRef.scala:132)
[error] akka.testkit.TestActorRef$.apply(TestActorRef.scala:125)
[error] test.ScannerTest$$anonfun$1$$anonfun$apply$3.apply(ScannerTest.scala:27)
[error] test.ScannerTest$$anonfun$1$$anonfun$apply$3.apply(ScannerTest.scala:23)
[error] akka.actor.LocalActorRef.<init>(Lakka/actor/ActorSystemImpl;Lakka/actor/Props;Lakka/actor/InternalActorRef;Lakka/actor/ActorPath;)V
[error] akka.testkit.TestActorRef.<init>(TestActorRef.scala:21)
[error] akka.testkit.TestActorRef$.apply(TestActorRef.scala:135)
[error] akka.testkit.TestActorRef$.apply(TestActorRef.scala:132)
[error] akka.testkit.TestActorRef$.apply(TestActorRef.scala:125)
[error] test.ScannerTest$$anonfun$1$$anonfun$apply$3.apply(ScannerTest.scala:27)
[error] test.ScannerTest$$anonfun$1$$anonfun$apply$3.apply(ScannerTest.scala:23)
[info] Total for specification ScannerTest
[info] Finished in 86 ms
[info] 1 example, 0 failure, 1 error
[info] test.ScannerTest
I believe that I need to create a FakeApplication and use that FakeApplication's Akka.system; however, I am not sure how to do it. To be honest, I am not even sure if that is the correct approach. If I could just generate a generic Akka.system and have that work I'd be ecstatic. If anyone has any ideas on how to tackle this I'd be really appreciative.
Okay, I figured it out. Make sure you are using the correct version of akka-testkit. In Play 2.2.0 I was trying to use akka 2.2.M3. Obviously, that doesn't work. I had to put the correct dependencies in my Build.scala, which ended up being this:
"com.typesafe.akka" %% "akka-testkit" % "2.2.0" % "test"
My actual test code looks like this:
package test
import org.specs2.mutable._
import controllers.Scanner
import java.util.UUID
import org.joda.time.DateTime
import akka.testkit.TestActorRef
import play.api.Logger
import models.PSqlEnum
import akka.actor.ActorSystem
import com.typesafe.config.ConfigFactory
import scala.concurrent.ExecutionContext.Implicits.global
class ScannerTest extends Specification {
val appId = UUID.randomUUID()
val app = models.App(appId, "TestApp", "TestServer", "TestComponent", "Test Description", DateTime.now(),
DateTime.now(), true, 3, 60, PSqlEnum("scanType", "mandatory"), "http://localhost")
val rules = <Rule name="DivisionDataIsAvailable" elementsToCheck="DivisionDataIsAvailable"
ruleType="is, true, yellow" />
<Rule name="DivisionDataLoadIsHealthy" elementsToCheck="DivisionDataLoadIsHealthy"
ruleType="is, true, red" />;
"Scanner" should {
"test something" in {
implicit val actorSystem = ActorSystem("testActorSystem", ConfigFactory.load())
val scanner = TestActorRef(new Scanner(app, rules)).underlyingActor
val response = scanner.getResponseFromWebService
response onSuccess {
case result => Logger.warn(result.toString)
}
response onFailure {
case error => Logger.warn(error.toString)
}
1 === 1
}
}
}
Obviously again, this test isn't really doing anything. The actual test being evaluated is 1 === 1. It does print out to the log now though which means I can go back and verify datatypes and the payload of the response, and then build some actual Unit Tests. I hope someone finds this useful. Those error messages in the original question are caused by the akka-testkit dependency not being the same version as Akka though, which might be useful for someone.
I'm not using spec2 or Mockito but here is what I'm doing to unit test Akka actors in Play 2.2.1:
import org.specs2.mutable.Specification
import scala.concurrent.duration._
import org.scalatest.concurrent._
import akka.testkit._
import org.scalatest.matchers.ShouldMatchers
import org.scalatest.{FlatSpec, BeforeAndAfterAll}
import akka.actor.{Props, ActorSystem}
import akka.pattern.ask
import akka.util.Timeout
import scala.util.{Failure, Success}
import model.BlacklistEntry
import scala.concurrent.{Future, Promise, Await}
import scala.concurrent.ExecutionContext.Implicits.global
import play.api.test.FakeApplication
import model.BlacklistEntryImpl
class LicenceBlackListSpec(_system: ActorSystem) extends TestKit(_system) with ImplicitSender with ShouldMatchers with FlatSpec with BeforeAndAfterAll {
play.api.Play.start(FakeApplication())
import akka.testkit.TestKit._
def this() = this( ActorSystem("LicenceBlackListSpec") )
override def afterAll: Unit = {
system.shutdown()
system.awaitTermination(10.seconds)
}
implicit val timeout = Timeout(10 seconds)
val blacklistRef = TestActorRef(Props[LicenceBlackList])
"An LicenceBlackList Actor" should "be able to create a new blacklist entry" in {
blacklistRef ! CreateEntry(BlacklistEntryImpl("NEW_KEY",1000,"Test creation"))
val expected: BlacklistEntry = BlacklistEntryImpl("NEW_KEY", 1000 ,"Test creation")
expectMsg( expected )
}
}
You'll need to include the scalatest lib as a dependency as well akka test kit:
"org.scalatest" % "scalatest_2.10" % "1.9.1"
Hope this will help.
I don't use ActorSystem("testActorSystem" ) , I have tryed to allow play framework to use it's usual akka plugin. This approach has folowing benefits: I can use play.api.libs.concurrent.Akka.system in all code, I can have extra config options that understand booth play and akka code parts .
class BaseActorTester (_app: Application) extends akka.testkit.TestKit(play.api.libs.concurrent.Akka.system(_app)) with FunSuiteLike with BeforeAndAfterAll {
def this() = this(FakeApplication(additionalConfiguration=Map("currency.db"->"airando-test")))
implicit val app: Application = _app
implicit val ec = play.api.libs.concurrent.Akka.system.dispatcher
override def beforeAll {
Play.start(app)
}
// play plugin do it itself ??
//override def afterAll {
// akka.testkit.TestKit.shutdownActorSystem(system)
//}
...
}