Munit - Testing sub-flow - mule

I am having a flow as follows
<flow name="MyMainFlow">
<flow-ref name="MySubFlow" >
</flow>
<sub-flow name="MySubFlow">
------
</sub-flow>
While testing with Munit I am getting class not found exception . Due to some reasons I am not allowed to test through mule files . Is there any way where I could test sub-flow with Munit?

I was able to test a sub flow using the following flow and sub-flow:
<flow name="main">
<vm:inbound-endpoint path="in"/>
<flow-ref name="MySubFlow" />
<vm:outbound-endpoint path="out"/>
</flow>
<sub-flow name="MySubFlow">
<append-string-transformer message=" Received"/>
</sub-flow>
and the following munit test:
<munit:test name="test" description="Create your test here">
<munit:set payload-ref="#[string: Hello world!]"/>
<munit:assert-not-null/>
</munit:test>

You can do a flow ref to a sub flow
https://github.com/mulesoft/munit/blob/munit-3.5.x/munit-integration-tests/src/test/munit/assertion-munit-test.xml#L83
The class not found exception is related with your test classpath, can we have a stacktrace?

Subflow can be tested from parent flow which called by using the flow -ref.
you can try with latest versions of munit 3.5.2-m2 version.

Related

mule 4 sftp file read is deleting file after file read

Using Mule 4.4 community edition .
I am reading a file using mule's sftp connector :
<dependency>
<groupId>org.mule.connectors</groupId>
<artifactId>mule-sftp-connector</artifactId>
<version>1.4.1</version>
<classifier>mule-plugin</classifier>
</dependency>
Running code in dedug mode , after the file is read , I can still see the file on sftp location ( which is good ) , however it disappears after file read .... ( see below code )
<sftp:config name="SFTP_Config" doc:name="SFTP Config"
timeBetweenSizeCheck="30" timeBetweenSizeCheckUnit="SECONDS">
<sftp:connection host="myHost" port="22" username="myUser" password="myPassword" />
</sftp:config>
<until-successful maxRetries="1" doc:name="Until Successful" millisBetweenRetries="30000">
<sftp:read doc:name="Read employee file" config-ref="SFTP_Config" path="${sftp.inputDir}\employee.unl" timeBetweenSizeCheck="-1" outputMimeType="application/csv; streaming=true; header=false; separator=|" outputEncoding="UTF-8">
<non-repeatable-stream />
</sftp:read>
</until-successful>
<choice doc:name="is the file empty ?" >
<when expression="sizeOf(payload) == 0">
<raise-error doc:name="Raise error on empty file " type="FILE_NOT_PRESENT_OR_EMPTY" description="Employee File empty "/>
</when>
<otherwise >
<logger level="INFO" doc:name="Payload not empty" message=" #[sizeOf(payload)]" category="employee"/>
</otherwise>
</choice>
So when the code enters the choice condition I can see the file is somehow no longer available on SFTP drive ...
I have tested this code in debug mode to verify when the file is getting deleted / disappearing.
Not sure why this would happen ?
why is the file getting deleted after code enters into the choice condition ?

How to store data from a .properties file in a variable in Mulesoft Anypoint Studio?

I've got a few .properties files containing some data. How do I write a specific value of a property from one of the property files to a variable?
There are the following three approaches to perform on this problem statement.
1.Reading a properties file using ${Key} expression
2.Reading a properties file using ![p[‘Key’]] expression
3.Reading a properties file using p() function from DataWeave
While according to your need, I have used the first approach. Please go through the following code. I think this will resolve your problem.
<http:listener-config name="HTTP_Listener_Configuration" host="0.0.0.0" port="8081" doc:name="HTTP Listener Configuration"/>
<context:property-placeholder location="propread.properties"/>
<flow name="propreadFlow">
<http:listener config-ref="HTTP_Listener_Configuration" path="/propread" doc:name="HTTP"/>
<logger message=""Flow Started"" level="INFO" doc:name="Logger"/>
<set-variable variableName="prop" value="${prop.read}" doc:name="Variable"/>
<logger message="#[flowVars.prop]" level="INFO" doc:name="Logger"/>
</flow>
</mule>
Please create one property file under src/main/resources with the name propread.properties and copy this ( prop.read=HelloMule ) into the file and run the above code. You will get the solution.

Mule: Memory Leak on use a custom-transformer at the end of flow

We process XML-Files from the Filesystem and once they've been process, they will be moved to another directory. Another system monitors this output folder and takes all newly created files for further process.
If we define the moveToPattern and moveToDirecory properties, the input file will be first copied to destinations and then deleted from input folder. This works properly on small files but takes longer on huge files which causes to incomplete file on output folder for some seconds.
Our solution is to let the file be copied with .tmp extension and then rename it to the final name and delete the input file.
So the Flow looks like below:
Input-File --> Processing --> Output-File with .tmp --> Rename --> Delete Input-File
The Problem is through using this custom-transformer for renaming the file after the file:endpoint the flow remains active and all Messages won't be garbage collected and causes a OutOfMemory Exception.
A Memory Dump shows a huge number of DefaultMuleMessage object which proofs my assumption.
has anybody an Idea to resolve this Problem?
<file:connector name="inputFileConnector" autoDelete="false" doc:name="File" streaming="true" validateConnections="true" />
<file:connector name="temporaryFileOutputConnectorConfig" outputPattern="#[message.outboundProperties['transportFileName']].tmp" autoDelete="false" streaming="false" validateConnections="true" doc:name="File" />
<file:endpoint path="${outputDir}/${queuePrefix}#[message.outboundProperties.'queue_number' ]/#[message.outboundProperties.'approvalSubDir']" name="OutputConnectorEndpoint" responseTimeout="10000" doc:name="File"/>
<flow name="Queue_Flow" processingStrategy="synchronous" initialState="stopped" >
<file:inbound-endpoint path="${inputDir}" responseTimeout="10000" pollingFrequency="5000" connector-ref="inputFileConnector" doc:name="File">
.
.
.
<flow-ref name="OutStrategyFile" doc:name="Out Strategy File"/>
</flow>
<sub-flow name="OutStrategyFile">
<file:outbound-endpoint connector-ref="temporaryFileOutputConnectorConfig" responseTimeout="10000" ref="OutputConnectorEndpoint" doc:name="Write temporary file"/>
<custom-transformer class="com.fileutil.FileRenamer" doc:name="Rename file to final location">
<spring:property name="fileUtils" ref="fileUtils"/>
</custom-transformer>
<custom-transformer class="com.fileutil.DeleteOriginalInputMessage" doc:name="Delete Original input message"/>
</sub-flow>

Delete Files in source directory if processing fails

My requirement is to process a file at an inbound endpoint
Use Case 1- Failure in processing the file
If the file fails processing due to some exception like a validation error move the file to a separate directory different from the source. Delete the original file in the source directory
Use Case 2 -Successful processing
If the file processing is successful done , let the file remain in the source directory.
I tried the following , the file is moved to failed directory but the source file is not deleted as required in Use Case 1.
<flow name="InValidFlow1" doc:name="InValidFlow1">
<file:inbound-endpoint responseTimeout="10000" doc:name="File" path="c:\filelanding\in2" pollingFrequency="100" connector-ref="input_2" moveToDirectory="c:\filelanding\in2" moveToPattern="#[header:originalFilename]-#[function:dateStamp]-Processed">
<file:filename-regex-filter pattern="(?!.*Processed|.*Failed)(.*)" caseSensitive="false"/>
</file:inbound-endpoint>
<test:component waitTime="20000"></test:component>
<custom-transformer class="com.XXX.XXX.service.ExceptionService" doc:name="Java"/>
<file:outbound-endpoint responseTimeout="10000" doc:name="File" path="c:\filelanding\out2" connector-ref="output_2"/>
<exception-strategy ref="fot_exception_strategy_single" doc:name="Reference Exception Strategy"/>
</flow>
<file:connector name="error_output_1" outputPattern="#[header:originalFilename]" doc:name="File"/>
<choice-exception-strategy name="fot_exception_strategy_single">
<catch-exception-strategy when="#[exception.causedBy(java.lang.RuntimeException)]" doc:name="Catch Exception Strategy">
<!-- Mark the status as failed-->
<file:outbound-endpoint connector-ref="error_output_1" responseTimeout="10000" doc:name="File" path="c:\filelanding\backup2" outputPattern="#[header:originalFilename]-#[function:dateStamp]-Failed" >
</file:outbound-endpoint>
</catch-exception-strategy>
</choice-exception-strategy>
Do i need to override any existing mule functionality to achieve this behavior. The source folder on failure shouldn't contain the file. The destination folder should have the file marked with "Failed" status.
For use case 1, in your exception strategy use the value in originalFilename in a MEL expression component to move the file to wherever you want.
You can use org.mule.util.FileUtils.moveFileWithCopyFallback() for that matter.
PS. #[header:originalFilename] is old style expression syntax, on Mule 3.3 and above use MEL #[message.inboundProperties.originalFilename].

mule custom transformer works in studio, but not deployed to standalone server

I have a flow with a custom transformer. This flow works when I run it under Mule Studio, but fails when run by the mule standalone server. The error message is "No class for element custom-transfomer(name=Update Table)"
<flow name="updates" doc:name="updates">
<jms:inbound-endpoint connector-ref="JMSConnector"
doc:name="JMS" topic="updates" />
<collection-splitter doc:name="Collection Splitter" />
<custom-transformer class="com.domain.UpdateTable"
doc:name="Update Table">
<spring:property name="table" ref="table" />
</custom-transformer>
</flow>
I also found a similar question in the old mule forum, but it had no answer;
This error was caused by a java.lang.NoClassDefFoundError, which Mule catches and converts into the "No class for element" message. Here's a good description of NoClassDefFoundError. In my case the error was caused by an exception thrown from a static initializer.