My project has already existing end to end scenario using another tool. We are reproducing our scenario using NoraUI. The scenario is reproduced and working but with hard-coded testing data.
We would like to reproduce the dynamic testing data generation we had on our project into this one but it's a quite complicated way to generate them as
we have multiple query on our database which can change depending on result of precedents one and other conditions.
It seems at the moment there is only three way to inject data into the scenario:
XLSX File
CSV File
Single Query to DB
And this happen through the ScenarioInitiator which is launched at the very beginning of the run.
Is there a way to add a custom way to inject data into a scenario, or for example to generate the data inside the XLSX file before its data are injected without the need of another project ?
Create a new pakage « noraui.data.xxx » (Example : « noraui.data.json »)
Create a new java class (Example : « CustomJsonDataProvider »)
Extend this class to “CommonDataProvider » and implement to « DataInputProvider » and « DataOutputProvider »
In your XxxxxRobot.properties file:
# type of dataProvider (EXCEL, CSV, DB, REST, noraui.data.xxx.YourCustomDataProvider)
dataProvider.in.type=noraui.data.json.CustomJsonDataProvider
dataProvider.out.type=noraui.data.json.CustomJsonDataProvider
Sample of CustomJsonDataProvider class:
package noraui.data.json;
import noraui.data.CommonDataProvider;
import noraui.data.DataInputProvider;
import noraui.data.DataOutputProvider;
import noraui.exception.TechnicalException;
public class CustomJsonDataProvider extends CommonDataProvider implements DataInputProvider, DataOutputProvider {
public CustomJsonDataProvider() {
super();
logger.info("data provider used is ...");
}
#Override
public void prepare(String scenario) throws TechnicalException {
// TODO Auto-generated method stub
}
#Override
public void writeFailedResult(int line, String value) throws TechnicalException {
// TODO Auto-generated method stub
}
#Override
public void writeWarningResult(int line, String value) throws TechnicalException {
// TODO Auto-generated method stub
}
#Override
public void writeSuccessResult(int line) throws TechnicalException {
// TODO Auto-generated method stub
}
#Override
public void writeDataResult(String column, int line, String value) throws TechnicalException {
// TODO Auto-generated method stub
}
#Override
public int getNbLines() throws TechnicalException {
// TODO Auto-generated method stub
return 0;
}
#Override
public String readValue(String column, int line) throws TechnicalException {
// TODO Auto-generated method stub
return null;
}
#Override
public String[] readLine(int line, boolean readResult) throws TechnicalException {
// TODO Auto-generated method stub
return null;
}
}
Related
Can I use Spring Data Redis #Repositories, and a CachingConfigurer to implement error handling? For instance -
#Override
public CacheErrorHandler errorHandler() {
return new RedisCacheError();
}
Using the CacheConfigurer above along with the repository as defined below, note the use of CrudRepository operations.
#Repository
public interface ObjectRepository extends CrudRepository<object, String>
I notice that CrudRepository has operations such as save, wondering if that is doing a redis.add() in the background? And basically whether or not the ErrorHandler see below, will actually catch errors on the save operation.
public class RedisCacheError implements CacheErrorHandler {
#Override
public void handleCacheGetError(RuntimeException exception,
Cache cache, Object key) {
log.info("caught error in here: " + exception );
}
#Override
public void handleCachePutError(RuntimeException exception, Cache cache,
Object key, Object value) {
log.info("caught error in here: " + exception );
}
#Override
public void handleCacheEvictError(RuntimeException exception, Cache cache,
Object key) {
//Do something on error while Evict cache
}
#Override
public void handleCacheClearError(RuntimeException exception,Cache cache){
//Do something on error while clearing cache
}
}
I'm having two routes in two separated projects :
First route is setting the header with a data format bean name as a constant :
setHeader("dataFormatBeanName", constant("myFirstList"))
First route :
public class MyTest {
#Configuration
public static class MyTestConfig extends CamelConfiguration {
#Bean(name = "myFirstList")
public DataFormat getMyFirstListDataFormat() {
return new MyFirstListDataFormat();
}
#Bean(name = "mySecondList")
public DataFormat getMySecondListDataFormat() {
return new MySecondListDataFormat();
}
#Bean
public RouteBuilder route() {
return new RouteBuilder() {
#Override
public void configure() throws Exception {
from("direct:testFirstDataFormat").setHeader("dataFormatBeanName", constant("myFirstList")).to("direct:myRoute");
from("direct:testSecondDataFormat").setHeader("dataFormatBeanName", constant("mySecondList")).to("direct:myRoute");
}
};
}
}
}
Second route is supposed to retrieve the bean name from the header and use it as a custom marshaller. Something like :
custom(header("dataFormatBeanName"))
(doesn't compile)
Anyone knows how I'm supposed to get my bean name from the header to use it in the custom method ?
#Component
public class MyRouteBuilder extends RouteBuilder {
#Override
public void configure() throws Exception {
final RouteDefinition routedefinition = this.from("direct:myRoute");
routedefinition.marshal().custom(??????????).to("netty4:tcp://{{route.address}}:{{port}}?textline=true&sync=true");
}
After a few more hours searching, here is the solution a found :
No changes in the first class.
Second class uses an anonymous DataFormat in which I retrieve the bean name from the header and get the spring bean from camel context before calling its marshal method.
The AbstractXxxDataFormat class belongs to project2 and is inherited by the Project1 DataFormat.
#Override
public void configure() throws Exception {
final RouteDefinition routedefinition = this.from("direct:myRoute");
routedefinition.marshal(new DataFormat() {
#Override
public void marshal(final Exchange exchange, final Object graph, final OutputStream stream) throws Exception {
AbstractXxxDataFormat myDataFormat = (AbstractGoalDataFormat) getContext().getRegistry().lookupByName(exchange.getIn().getHeader("dataFormatBeanName", String.class));
myDataFormat.marshal(exchange, graph, stream);
}
#Override
public Object unmarshal(final Exchange exchange, final InputStream stream) throws Exception {
return null;
}
});
routedefinition.to("netty4:tcp://{{route.address}}:{{port}}?textline=true&sync=true");
}
If there's any better solution available, I'll be interested.
Have you tried simple("${header.dataFormatBeanName}") to access the header?
Also, rather than passing the format bean name in a header in the first place, why not factor out each .marshal() call into two subroutes (one for formatBeanA and one for formatBeanB) and then call the appropriate subroute rather than setting the header in the first place? I believe this could be a cleaner approach.
If you really need to get it in the route as a variable (as opposed to a predicate to be used in the builder api) you could use an inline processor to extract it:
public class MyRouteBuilder extends RouteBuilder {
public void configure() throws Exception {
from("someEndpoint")
.process(new Processor() {
public void process(Exchange exchange) throws Exception {
String beanName = exchange.getHeader("beanNameHeader");
}
});
}
}
Just be careful of scope and concurrency when storing the extracted beanName however.
A collegue of mine (thanks to him) found the definite solution :
set bean name in the exchange properties :
exchange.setProperty("myDataFormat", "myDataFormatAutowiredBean");
retrieve the dataFormat bean with RecipientList pattern and (un)marshal :
routedefinition.recipientList(simple("dataformat:${property.myDataFormat}:marshal"));
routedefinition.recipientList(simple("dataformat:${property.myDataFormat}:unmarshal"));
Very concise and works just fine.
i have this class
#Value("${norsys.loadfile.directory}")
private String chemin;
#RequestMapping(value = "/{fileName:.+}", method = RequestMethod.GET)
#ResponseBody()
public void loadVideoFile(#PathVariable("fileName") String fileName,HttpServletResponse response) {
try {
response.setContentType("video/mp4");
Files.copy(Paths.get(chemin, fileName), response.getOutputStream());
response.flushBuffer();
} catch (java.io.FileNotFoundException e) {
response.setStatus(HttpStatus.NOT_FOUND.value());
} catch (Exception e) {
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
}
}
I dont know how to apply a JUnit test to keep coverage high, I hope that you can give me an idea, thank you
In general you can use Mockito http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html to test classes which have heavyweight dependencies. Using a mock HttpServletResponse class you could verify that the status code is set appropriately for your failure/success cases.
You're going to run into some problems with the use of those static methods.
Instead of
Files.copy(Paths.get(chemin, fileName), response.getOutputStream());
You could use a non-static class, which you could then mock
class ResourceCopier {
public void copy(String dir, String file, OutputStream os) {
Files.copy(Paths.get(dir, file), os);
}
}
Your main class uses
private ResourceCopier resourceCopier;
public void loadVideoFile(....) {
resourceCopier.copy(chemin, fileName, response.getOutputStream());
}
And in your test class you create your primary object, create a Mock of ResourceCopier and HttpServletResponse and use #InjectMocks to inject them to your primary object.
You can then use Mockito's verify() method to make sure the right things have happened (like response.setStatus called with 404 code)
I have a class that only have main which read in some txt and do the algorithms.
my class is look like:
class doThejob{
public static void main(String args[]){
//*****start part A******
//do the reading from text file, and tokenize it
// process into the form I need,
//about 10-30 lines of codes
//******End of part A*****
//then run the algorithms
algorithm alg=new aglorithm();
Object output = alg.x(input);
//****Part B**** output to txt, about 10~40 lines
}
}
class algorithm{
private void a(Object x){
//do something
return (Object)result;
}
}
Can anyone tell me should I extract those part A and part B to a new class ,and then setup them as a public method .like below
class Io{
public Object readFromTxt(String path){
}
public void outputToTxt(String path){
}
}
And if I setup them , and then use it like below, is that more OOP?
class doThejob{
public static void main(String args[]){
Io dataProcess= new Io();
Object input = dataProcess.readFromTxt(args[0]);
algorithm alg=new aglorithm();
Object output =alg.x(input);
dataProcess.readFromTxt(args[1],output);
}
}
class algorithm{
private Object a(Object x){
//do something
}
}
Do it the way you fill is more readable.
Separating this in another class is according to the Single Responsability Principle. It will help making the code more readable and easy to change later on.
If you want to expand more on this, you could create an interface (eg.: IIO) for input and output. This way you can implement this interface in the IO class, renaming it to FileIO. Anytime you want to create another form of IO, like database access, you just have to create a DatabaseIO class that implements this interface and change the instance in the main method for this new type:
public interface IIO
{
string Read();
void Write(string text);
}
public class FileIO : IIO
{
string path;
public FileIO(string filePath)
{
path = filePath;
}
public string Read()
{
// read from file and return contents
}
public void Write(string text)
{
// write to file
}
}
public class SqlServerIO : IIO
{
SqlConnection conn;
public SqlServerIO(string connectionStringName)
{
// create the connection
}
public string Read()
{
// read from database
}
public void Write(string text)
{
// write to database
}
}
Extracting interfaces makes the code more maintenable by alowing to switch implementations anytime without messing with working code. It also facilitates unit testing.
I am using the Subclipse API and I would like to implement the ISVNNotifyListener so that I can find out about the subclipse events as they happen during runtime. I believe I need to add (subscribe) my instance of the notify listener to the set of listeners that the Client Adapter will notify, but I am at a loss for how to get access to the Client Adapter that is being used by Subclipse at runtime. Is there a way to access it so that I can add my listener to the set?
Sorry, but unfortunately Subclipse has not been coded in such a way to provide access to the internals. Subclipse constructs a new ISVNClientAdapter object for each API call it needs to make into Subversion and it adds its ISVNNotifyListener to this object on the fly as needed. So there is no way for you to interject your own listener.
Perhaps you could write a class that implements IConsoleListener and have it act as a proxy for the Subclipse class. You could then call SVNProviderPlugin.getConsoleListener to get the current console listener and store a reference to it in your class. Then call SVNProviderPlugin.setConsoleListener to replace the class held in Subclipse with your class. As the events are fired in your class, you could just forward them on to the Subclipse class and do whatever you want with the events in your code. Something like this:
import java.io.File;
import org.tigris.subversion.subclipse.core.client.IConsoleListener;
import org.tigris.subversion.svnclientadapter.SVNNodeKind;
public class ProxyListener implements IConsoleListener {
private IConsoleListener subclipseListener;
public ProxyListener(IConsoleListener subclipseListener) {
super();
this.subclipseListener = subclipseListener;
}
public void setCommand(int command) {
subclipseListener.setCommand(command);
// TODO add your code
}
public void logCommandLine(String commandLine) {
subclipseListener.logCommandLine(commandLine);
// TODO add your code
}
public void logMessage(String message) {
subclipseListener.logMessage(message);
// TODO add your code
}
public void logError(String message) {
subclipseListener.logError(message);
// TODO add your code
}
public void logRevision(long revision, String path) {
subclipseListener.logRevision(revision , path);
// TODO add your code
}
public void logCompleted(String message) {
subclipseListener.logCompleted(message);
// TODO add your code
}
public void onNotify(File path, SVNNodeKind kind) {
subclipseListener.onNotify(path, kind);
// TODO add your code
}
}