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

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.

Related

Eclipse JUnit 5 SecruityException when running Tests

I think I may be the only one experiencing this issue.
I, today, updated my eclipse install to version 2020-03 (4.15.0). I am also attempting to write a very simple JUnit 5 test for a new method I'm working on.
When I run my test, right now just a basic stub, I get the following error:
java.lang.SecurityException: class "org.junit.platform.commons.PreconditionViolationException"'s signer information does not match signer information of other classes in the same package
at java.base/java.lang.ClassLoader.checkCerts(ClassLoader.java:1150)
at java.base/java.lang.ClassLoader.preDefineClass(ClassLoader.java:905)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1014)
at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:151)
at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:821)
at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:719)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:642)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:600)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
at org.eclipse.jdt.internal.junit5.runner.JUnit5TestLoader.createUnfilteredTest(JUnit5TestLoader.java:75)
at org.eclipse.jdt.internal.junit5.runner.JUnit5TestLoader.createTest(JUnit5TestLoader.java:66)
at org.eclipse.jdt.internal.junit5.runner.JUnit5TestLoader.loadTests(JUnit5TestLoader.java:53)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:526)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:770)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:464)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
I also see the following dialog
My run Configuration is:
I've tried all major junit-jupiter (aggregator) releases back to 5.5.0 all resulting in the same issue.
I've tried this solution. However, that question deals with a class not found issue. I also tried that same solution using using junit-platform-commons version 1.6.1. no change.
However, I can run maven configuration with -Dtest=DeaFileListTest test the the tests run.
My test case is simple, I instantiate an object that has the method I want to test and then my test.
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.not;
import java.io.IOException;
import java.util.List;
import javax.ws.rs.core.Response;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import com.mfgweb.FileRepo;
class DeaFileListTest {
private static FileRepo filerepo;
private static Response response;
#BeforeAll
static void setUpBeforeClass() throws Exception {
filerepo = new FileRepo();
response = filerepo.getDeaFiles();
}
#AfterAll
static void tearDownAfterClass() throws Exception {
response = null;
filerepo = null;
}
#Test
public void deaFileListIsNotEmptyTest() throws IOException {
#SuppressWarnings ( "unchecked" )
List< String > files = ( List< String > )response.getEntity();
assertThat( files, not( empty() ) );
}
}
So I am curious why I'm receiving the Security Exception when I run the test in eclipse, yet Maven seems to execute them fine.

Citrus framework: How to make a soap response / citrus variable / citrus function return result available to java

I'm using Citrus 2.7.8 with Cucumber 2.4.0. I'm making a soap call and want to get the response and do some advanced parsing on it to validate a graphql response has matching values. (I understand how to do validations when it's something that just has one element, but I need something able to handle when there could be one or many elements returned (for example, 1 vehicle or 4 vehicles)). To make my validation very dynamic and able to handle many different 'quotes', I want to store the response to a Citrus variable and then make it available to java to read in the file and do the advanced parsing and validation.
The TestContext injection doesn't appear to currently work with cucumber (see https://github.com/citrusframework/citrus/issues/657) so I'm using the workaround here:
How to inject TestContext using TestRunner and cucumber to manually create the context. Without this I get a nullpointerexception on anything with the context.
I am able to use Citrus's message function to grab the soap response which is awesome. My echo statements in the console show that it successfully put the right value into the citrus variable. But I'm having problems making that available to java so that I can then open it up and parse through it.
I've scaled down my step definition file to just the pertinent code. My couple attempts are listed below along with the problems I encountered in their results.
Does anyone have any ideas on how I can successfully workaround the context issues and make my response available to java?
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import com.consol.citrus.Citrus;
import com.consol.citrus.annotations.CitrusFramework;
import com.consol.citrus.annotations.CitrusResource;
import com.consol.citrus.config.CitrusSpringConfig;
import com.consol.citrus.context.TestContext;
import com.consol.citrus.dsl.junit.JUnit4CitrusTestRunner;
import com.consol.citrus.dsl.runner.TestRunner;
import com.consol.citrus.ws.client.WebServiceClient;
import cucumber.api.java.en.When;
#ContextConfiguration(classes = CitrusSpringConfig.class)
public class CitrusSteps extends JUnit4CitrusTestRunner {
#CitrusFramework
private Citrus citrus;
#CitrusResource
private TestRunner runner;
#CitrusResource
private TestContext context;
#Autowired
private WebServiceClient getQuote;
#When("^I call getQuote with id \"([^\"]*)\"$")
public void i_call_getquote_with_id(String quoteId) throws Throwable {
context = citrus.createTestContext();
String soappayload = "my payload (taken out for privacy purposes)";
runner.soap(action -> action.client(getQuote)
.send()
.soapAction("getQuote")
.payload(soappayload));
runner.soap(action -> action.client(getQuote)
.receive()
.name("getQuoteResponseStoredMessage"));
//this bombs out on the context line with this: "com.consol.citrus.exceptions.CitrusRuntimeException: Unknown variable 'messageStoreGetQuoteResponse1'"
runner.variable("messageStoreGetQuoteResponse1", "citrus:message(getQuoteResponseStoredMessage.payload())");
runner.echo("First try: ${messageStoreGetQuoteResponse1}");
String firstTry = context.getVariable("messageStoreGetQuoteResponse1");
log.info("First Try java variable: " + firstTry);
//this bombs out on the context line with this: "com.consol.citrus.exceptions.CitrusRuntimeException: Unknown variable 'messageStoreGetQuoteResponse2'"
runner.createVariable("messageStoreGetQuoteResponse2", "citrus:message(getQuoteResponseStoredMessage.payload())");
runner.echo("Second try: ${messageStoreGetQuoteResponse2}");
String secondTry = context.getVariable("messageStoreGetQuoteResponse2");
log.info("Second Try java variable: " + secondTry);
//This stores the literal as the value - it doesn't store the message so it appears I can't use citrus functions within the context
context.setVariable("messageStoreGetQuoteResponse3", "citrus:message(getQuoteResponseStoredMessage.payload())");
String thirdTry = context.getVariable("messageStoreGetQuoteResponse3");
log.info("Third Try java variable: " + thirdTry);
}
}
A smart co-worker figured out a workaround for the injection not working w/ cucumber.
I replaced these two lines:
#CitrusResource
private TestContext context;
with these lines instead:
TestContext testContext;
public TestContext getTestContext() {
if (testContext == null) {
runner.run(new AbstractTestAction() {
#Override
public void doExecute(TestContext context) {
testContext = context;
}
});
}
return testContext;
}
Then within my step where I want the context, I can use the above method. In my case I wanted my message response, so I was able to use this and confirm that the response is now in my java variable:
String responseXML = getTestContext().getMessageStore().getMessage("getQuoteResponseStoredMessage").getPayload(String.class);
log.info("Show response XML: " + responseXML);

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!

CQ5 - displaying a CQ.Notification in the frontend, when a workflow finished

I implemented workflows, but it would be nice to know if there are hooks provided by the client library which allow to hook in. When a workflow was triggered and finished, a CQ.Notification should be displayed. Or do i need to implement a polling library by myself?
As far as I know, there is no built-in CQ area to see when something is done, aside from looking here:
http://yoursite.com:port/libs/cq/workflow/content/console.html
Once there, you can go to the 'Instances' tab and see what's happening.
In one application that I worked on, we ended up writing our own method that sends notifications to us based on one of our workflows (our workflow ties into it - from the workflow models area, you can set your process to be a servlet that you've put into CQ). Here is the main piece of code from our servlet that catches the process being active, and then calls our methods to email us based on what it finds:
import com.day.cq.workflow.WorkflowException;
import com.day.cq.workflow.WorkflowSession;
import com.day.cq.workflow.exec.WorkItem;
import com.day.cq.workflow.exec.WorkflowData;
import com.day.cq.workflow.exec.WorkflowProcess;
import com.day.cq.workflow.metadata.MetaDataMap;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import org.osgi.framework.Constants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import java.util.Arrays;
public class YourServletName implements WorkflowProcess {
#Override
public void execute(WorkItem workItem, WorkflowSession workflowSession, MetaDataMap args) throws WorkflowException {
session = workflowSession.getSession();
final WorkflowData data = workItem.getWorkflowData();
String type = data.getPayloadType();
String[] argStrings = args.get("PROCESS_ARGS", ARG_UPDATED).split(",");
String reason = argStrings[0];
String baseUrl = argStrings[1];
try {
if (type.equals(TYPE_JCR_PATH) && data.getPayload() != null) {
String resourcePath = data.getPayload().toString();
logger.info("Send Notification that {} has been {}.", resourcePath, reason.toLowerCase());
if (resourcePath != null && !resourcePath.isEmpty()) {
ResourceInfo resourceInfo = new ResourceInfo(resourcePath, baseUrl);
sendEmail(resourceInfo, reason);
}
}
} catch (EmailException ex) {
logger.warn("Failed to send Email");
throw new WorkflowException(ex);
} catch (MailingException ex) {
logger.warn("Failed to send Email");
throw new WorkflowException(ex);
}
}
}
You can find more info in the documentation for Extending Workflow Functionality.
Look at the first code block on that page, and that will give you the best idea of how you can implement a custom workflow handler.
EDIT
If you want to see it on the front-end, you could do an AJAX call to get the JSON list of currently running workflows - you can hit this url:
http://localhost:4502/etc/workflow/instances.RUNNING.json
Then you could loop through them and see if yours is in there. This isn't very nice though, since they are all just listed by IDs. I would instead suggest using the querybuilder, or again, just doing an AJAX GET. This is one example:
1_group.0_path=/etc/workflow/instances
2_group.0_type=cq:Workflow
0_group.property.2_value=COMPLETED
0_group.property=status
0_group.property.and=true
3_group.property=modelId
3_group.property.2_value=/etc/workflow/models/your-model-name/jcr:content/model
3_group.property.and=true
Then the URL would look something like this:
http://yoursiteurl:port/libs/cq/search/content/querydebug.html?_charset_=UTF-8&query=http%3A%2F%2Fyoursiteurl%3Aport%3F%0D%0A1_group.0_path%3D%2Fetc%2Fworkflow%2Finstances%0D%0A2_group.0_type%3Dcq%3AWorkflow%0D%0A0_group.property.2_value%3DRUNNING%0D%0A0_group.property%3Dstatus%0D%0A0_group.property.and%3Dtrue%0D%0A3_group.property%3DmodelId%0D%0A3_group.property.2_value%3D%2Fetc%2Fworkflow%2Fmodels%2Fyour-model-name%2Fjcr%3Acontent%2Fmodel%0D%0A3_group.property.and%3Dtrue
It's ugly, but it gets you the results you need, and then you can parse them to get further information you need.

Grails: Integration testing the Mail Plugin

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