Grails: Integration testing the Mail Plugin - email

I'm trying to integration test a class that uses the Mail Plugin. When I run my test (grails test-app -integration EmailerIntegration) I get the error:
Could not locate mail body layouts/_email. Is it in a plugin? If so you must pass the plugin name in the [plugin] variable
Is there some initialization code I'm missing from the setUp method of my test case?
Here is the code for the test case:
package company
import grails.test.*
class EmailerIntegrationTests extends GrailsUnitTestCase {
protected void setUp() {
super.setUp()
}
protected void tearDown() {
super.tearDown()
}
void testSomething() {
User owner = new User()
owner.displayName = "Bob"
owner.email = "bob#yahoo.com"
Emailer emailer = new Emailer()
emailer.sendReadyEmail(owner)
}
}
Here is the code for the class being tested:
package company
import org.apache.log4j.Logger;
import org.codehaus.groovy.grails.commons.ApplicationHolder;
import org.springframework.context.ApplicationContext;
class Emailer {
private Logger log = Logger.getLogger(this.getClass());
ApplicationContext ctx = (ApplicationContext)ApplicationHolder.getApplication().getMainContext();
def mailService = ctx.getBean("mailService");
def sendReadyEmail = { owner ->
mailService.sendMail {
to owner.email
subject "Ready to go"
body( view:"layouts/_email", model:[ownerInstance:owner])
}
}
}
Thanks,
Everett

After looking at the plugin author's own tests for the mail plugin at https://github.com/gpc/grails-mail/blob/master/test/integration/org/grails/mail/MailServiceTests.groovy I realized that the paths in the values for the view parameter all begin with a '/'. I changed my method to
def sendReadyEmail = { owner ->
mailService.sendMail {
to owner.email
subject "Ready to go"
body( view:"/layouts/_email", model:[ownerInstance:owner])
}
And now it works in integration tests and normal program execution.

The body parameter in the sendMail(..) method is a map with the keys view, model, and plugin. A value for plugin is required, and points to some other, supporting, plugin, for instance, the name "email-confirmation" for that corresponding plugin.
Your error message is thrown in org.grails.mail.MailMessageBuilder.renderMailView(Object, Object, Object). You can find this class in your Grails project's plugin folder.
Unfortunately, I haven't found too much documentation on the Mail plugin. Thus, at the moment, I cannot easily tell about how to use the aforementioned supporting plugins. If you can't get forward, however, I might try to further investigate. Thanks

Related

citrus waitFor().condition() statement not waiting when used with ftpServer

I'm trying to use the citrus-framework to test an integration that writes some files on a FTP server.
I need to wait until some file is uploaded to the ftp (I'm using waitFor().condition() statement to accomplish that) and then receive the messages sent and do some assertions.
import com.consol.citrus.annotations.CitrusTest;
import com.consol.citrus.condition.Condition;
import com.consol.citrus.context.TestContext;
import com.consol.citrus.dsl.testng.TestNGCitrusTestDesigner;
import com.consol.citrus.ftp.server.FtpServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ActiveProfiles;
import org.testng.annotations.Test;
import java.io.File;
#ActiveProfiles(value = "ftpTest")
#Test
public class FtpTest extends TestNGCitrusTestDesigner {
#Autowired
FtpServer ftpServer;
#Autowired
TestContext context;
#CitrusTest(name = "ftpTest")
public void ftpTest() {
// here I start my integration that uses a cron to upload the file
// this code is irrelevant for the example
Condition waitUntilFileIsUploaded = new Condition() {
#Override
public String getName () {
return "Check files on FTP";
}
#Override
public boolean isSatisfied (TestContext testContext){
return new File("/tmp/foo_dir").listFiles().length != 0;
}
#Override
public String getSuccessMessage (TestContext testContext){
return "Files found in FTP!";
}
#Override
public String getErrorMessage (TestContext testContext){
return "No file was found in FTP";
}
};
waitFor().condition(waitUntilFileIsUploaded).seconds(120L).interval(500L);
ftpServer.createConsumer().receive(context);
}
}
When I try to run this test looks like the waitFor() is never executed and ftpServer.createConsumer().receive(context); is executed before any file could be uploaded to the FTP.
This is the error that I'm getting:
ftpTest>TestNGCitrusTest.run:57->TestNGCitrusTest.run:111->TestNGCitrusTestDesigner.invokeTestMethod:73->TestNGCitrusTest.invokeTestMethod:133->ftpTest:49 » ActionTimeout
Any idea how I could fix this?
Also any complete example for using FTP Java DSL with Citrus would be more than welcome!
Please use test designer receive method instead of creating the consumer on your own.
receive(ftpServer)
.header("some-header", "some-value")
.payload("some payload");
Only then test designer can arrange the test actions in proper order. This is because test designer constructs the complete test action logic first and execution takes place at the very end of the test method.
As an alternative to that you could also use test runner instead of test designer. The runner will execute each test action immediately giving you the opportunity to add custom statements as you did before.

SWTBot Recorder Generated code bot.contextMenu not found

The following is the code generated by SWTBot Recorder.
public class UserInterfaceTester extends SWTBotEclipseTestCase {
#Test
public void TableTest() {
bot.tree().getTreeItem("wtrt").select();
bot.contextMenu("Expand All").click();
bot.tree().getTreeItem("wtrt").getNode("erwtesg(3)").getNode("esrgg").select();
bot.contextMenu("Open Application Metadata File").click();
bot.text().setText("9.5");
bot.text().setText("Synopsys");
bot.text().setText("3.2");
}
}
But when I try to put that in my Test case to run inside my project it shows error in bot.contextMenu. It says "The method contextMenu(String) is undefined for the type SWTEclipseBot".
Extending SWTBotEclipseTestCase automatically gives me bot object which is
protected SWTEclipseBot bot = new SWTEclipseBot();
But it says it is a deprecated version. It says "Deprecated. use SWTWorkbenchBot. This will be removed from future releases"
Hence I tried
SWTWorkbenchBot bot = new SWTWorkbenchBot(); // by removing extends SWTBotEclipseTestCase
that to did not work. What is the issue? Can some one help?
The ContextMenuHelper class should help with this, and it works round some bugs with dynamic context menus. try:
SWTBotMenu menu =
new SWTBotMenu(ContextMenuHelper.contextMenu(bot.tree(), "Expand All"));
menu.click();

Grails mail plugin delivery to console / log in development mode

I am using Grails with the mail plugin. In development mode I would like the mails my applications sends to be rendered (to catch bugs in the templates) but printed to the console.
The only option I found was
grails.mail.disabled=true
But, according to the documentation:
this will treat any call to mailService.sendMail() as a no-op
which is not quite what I want, since I want developers to be able to click on our confirmation links (for which I need the mail output).
Is there a nice way to "deliver" the mails to the console? I am aware that I could override the to-field with another address, but I'd rather not involve our mailserver when testing.
You could create your own dummy implementation of mailService as a class in src/groovy and then put some conditional code in grails-app/conf/spring/resources.groovy to define your dummy service only in development mode. The very simplest I can think of would be
src/groovy/com/example/DummyMailService.groovy
package com.example
import org.springframework.mail.MailMessage
class DummyMailService {
MailMessage sendMail(Closure callable) {
callable.delegate = new CallPrinter()
callable.call()
return null
}
}
class CallPrinter {
def methodMissing(name, args) {
println "${name}: ${args}"
}
}
grails-app/conf/spring/resources.groovy
import grails.util.Environment
beans = {
if(Environment.current == Environment.DEVELOPMENT) {
mailService(com.example.DummyMailService)
}
}
Obviously you could be cleverer, e.g. using a logger rather than println, or switching the dummy service based on a config option rather than just the environment (so you can turn on mail in dev mode later on when you specifically want to test it).
If you want to be able to handle body(view:'...', model:[:]) calls that render templates you could do that using the groovyPageRenderer:
class DummyMailService {
def callPrinter
MailMessage sendMail(Closure callable) {
callable.delegate = callPrinter
callable.call()
return null
}
}
class CallPrinter {
def groovyPageRenderer
def methodMissing(name, args) {
println "${name}: ${args}"
}
void body(Map params) {
methodMissing("body", groovyPageRenderer.render(params))
}
}
and in resources.groovy
mailService(com.example.DummyMailService) {
callPrinter = { com.example.CallPrinter p ->
groovyPageRenderer = ref('groovyPageRenderer')
}
}
GreenMail plugin is the closest to what you'd like that I can think of (see the plugin here). It will render the emails in a web page (the plugin provides a controller), not sure if you could set up Log4j to log the email to the console...

Play framework 2 + JPA with multiple persistenceUnit

I'm struggling with Play and JPA in order to be able to use two different javax.persistence.Entity model associated to two different persistence units (needed to be able to connect to different DB - for example an Oracle and a MySQL db).
The problem come from the Transaction which is always bind to the default JPA persitenceUnit (see jpa.default option).
Here is two controller actions which show the solution I found to manually define the persistence :
package controllers;
import models.Company;
import models.User;
import play.db.jpa.JPA;
import play.db.jpa.Transactional;
import play.mvc.Controller;
import play.mvc.Result;
public class Application extends Controller {
//This method run with the otherPersistenceUnit
#Transactional(value="other")
public static Result test1() {
JPA.em().persist(new Company("MyCompany"));
//Transaction is run with the "defaultPersistenceUnit"
JPA.withTransaction(new play.libs.F.Callback0() {
#Override
public void invoke() throws Throwable {
JPA.em().persist(new User("Bobby"));
}
});
return ok();
}
//This action run with the otherPersistenceUnit
#Transactional
public static Result test2() {
JPA.em().persist(new User("Ryan"));
try {
JPA.withTransaction("other", false, new play.libs.F.Function0<Void>() {
public Void apply() throws Throwable {
JPA.em().persist(new Company("YourCompany"));
return null;
}
});
} catch (Throwable throwable) {
throw new RuntimeException(throwable);
}
return ok();
}
}
This solution doesn't seem to be really "clean". I'd like to know if you know a better way to avoid the need to manually modify the transaction used.
For this purpose, I created a repo on git with a working sample application which shows how I configured the project.
https://github.com/cm0s/play2-jpa-multiple-persistenceunit
Thank you for your help
i met the same problem, too. too many advices are about PersistenceUnit annotation or getJPAConfig. but both them seem not work in play framework.
i found out a method which works well in my projects. maybe you can try it.
playframework2 how to open multi-datasource configuration with jpa
gud luk!

How to create a custom 404 page handler with Play 2.0?

What’s the preferred way to handle 404 errors with Play 2.0 and show a nice templated view?
You can override the onHandlerNotFound method on your Global object, e.g.:
object Global extends GlobalSettings {
override def onHandlerNotFound(request: RequestHeader): Result = {
NotFound(views.html.notFound(request))
}
}
Please note that there are really two different problems to solve:
Showing a custom 404 page when there is "no handler found", e.g. when the user goes to an invalid URL, and
Showing a custom 404 (NotFound) page as a valid outcome of an existing handler.
I think the OP was referring to #2 but answers referred to #1.
"No Handler Found" Scenario
In the first scenario, for "no handler found" (i.e. invalid URL), the other answers have it right but to be more detailed, per the Play 2.1 documentation as:
Step 1: add a custom Global object:
import play.api._
import play.api.mvc._
import play.api.mvc.Results._
object Global extends GlobalSettings {
override def onHandlerNotFound(request: RequestHeader): Result = {
NotFound(
views.html.notFoundPage(request.path)
)
}
}
Step 2: add the template. Here's mine:
#(path: String)
<html>
<body>
<h1>Uh-oh. That wasn't found.</h1>
<p>#path</p>
</body>
</html>
Step 3: tweak your conf/application.conf to refer to your new "Global". I put it in the controllers package but it doesn't have to be:
...
application.global=controllers.Global
Step 4: restart and go to an invalid URL.
"Real Handler can't find object" Scenario
In the second scenario an existing handler wants to show a custom 404. For example, the user asked for object "1234" but no such object exists. The good news is that doing this is deceptively easy:
Instead of Ok(), surround your response with NotFound()
For example:
object FruitController extends Controller {
def showFruit(uuidString: String) = Action {
Fruits.find(uuidString) match {
case Some(fruit) => Ok(views.html.showFruit(fruit))
// NOTE THE USE OF "NotFound" BELOW!
case None => NotFound(views.html.noSuchFruit(s"No such fruit: $uuidString"))
}
}
}
What I like about this is the clean separation of the status code (200 vs 404) from the HTML returned (showFruit vs noSuchFruit).
HTH
Andrew
If you want to do the same using Java instead of Scala you can do it in this way (this works for play framework 2.0.3):
Global.java:
import play.GlobalSettings;
import play.mvc.Result;
import play.mvc.Results;
import play.mvc.Http.RequestHeader;
public class Global extends GlobalSettings {
#Override
public Result onHandlerNotFound(RequestHeader request) {
return Results.notFound(views.html.error404.render());
}
}
Asumming that your 404 error template is views.html.error404 (i.e. views/error404.scala.html).
Please note that Play development team are making lots of efforts to move away from global state in Play, and hence GlobalSettings and the application Global object have been deprecated since version 2.4.
HttpErrorHandler.onClientError should be used instead of
GlobalSettings.onHandlerNotFound. Basically create a class that inherits from HttpErrorHandler, and provide an implementation for onClientError method.
In order to find out type of error (404 in your case) you need to read status code, which is passed as a one of the method arguments e.g.
if(statusCode == play.mvc.Http.Status.NOT_FOUND) {
// your code to handle 'page not found' situation
// e.g. return custom implementation of 404 page
}
In order to let Play know what handler to use, you can place your error handler in the root package or configure it in application.conf using play.http.errorHandler configuration key e.g.
play.http.errorHandler = "my.library.MyErrorHandler"
You can find more details on handling errors here: for Scala or Java.
This works in 2.2.1. In Global.java:
public Promise<SimpleResult> onHandlerNotFound(RequestHeader request) {
return Promise.<SimpleResult>pure(notFound(
views.html.throw404.render()
));
}
Ensure that you have a view called /views/throw404.scala.html
This works in 2.2.3 Play - Java
public Promise<SimpleResult> onHandlerNotFound(RequestHeader request) {
return Promise<SimpleResult>pure(Results.notFound(views.html.notFound404.render()));
}
html should be within /views/notFound404.scala.html
Dont forget to add Results.notFounf() and import play.mvc.Results;
For Java, if you want to just redirect to main page, I solved it by this.
#Override
public Promise<Result> onHandlerNotFound(RequestHeader request) {
return Promise.pure(redirect("/"));
}