I am trying to delete a certain handler from my handler pipeline, but I am having trouble doing it. When I list the handlers in the pipeline before and after, the handler that I tried to remove is still there. So what am I doing wrong here? Here is a code snippet. All of this is in the startup phase. You can see that last thing that I do is configure the pipeline factory. I am using Netty 3.6.1.final.
List<String> handlers = new ArrayList<String>();
// list handlers in the pipeline
try {
handlers = this.pipelineFactory.getPipeline().getNames();
for (int len = handlers.size(), i = 0; i < len; i++) {
String s = handlers.get(i);
System.out.println("Item " + i + " is " + s);
}
} catch( Exception e ) {}
try {
System.out.println("Remove hexdump");
this.pipelineFactory.getPipeline().remove("hexdump");
} catch( Exception e ) {
System.out.println("error = " + e.getMessage());
}
try {
handlers = this.pipelineFactory.getPipeline().getNames();
for (int len = handlers.size(), i = 0; i < len; i++) {
String s = handlers.get(i);
System.out.println("Item " + i + " is " + s);
}
} catch( Exception e ) {}
// Configure the pipeline factory.
this.bootstrap.setPipelineFactory(this.pipelineFactory);
Here is the output:
Item 0 is framer
Item 1 is hexdump
Item 2 is handler
Remove hexdump
Item 0 is framer
Item 1 is hexdump
Item 2 is handler
Not sure without checking out full code, but looks like pipelineFactor.getPipeline() will always create a new pipeline in your case. Since its a factory, it will be creating the handlers each time. Put in one more sysout for this.pipelineFactory.getPipeline() and if you are seeing 3 different object hashcodes then this is the root cause.
Solution could be pipeline = this.pipelineFactory.getPipeline(), and then using the pipeline for adding removing etc.
Also for the record, it seems wrong usage anyway, you should be getting the pipeline from the ChannelHandlerContext object either in a decode method or a messageReceived method of a handler.
Related
I'm actually developing a project that read data from 19 PLCs Siemens S1500 and 1 modicon. I have used the scraper tool following this tutorial:
PLC4x scraper tutorial
but when the scraper is working for a little amount of time I get the following exception:
I have changed the scheduled time between 1 to 100 and I always get the same exception when the scraper reach the same number of received messages.
I have tested if using PlcDriverManager instead of PooledPlcDriverManager could be a solution but the same problem persists.
In my pom.xml I use the following dependency:
<dependency>
<groupId>org.apache.plc4x</groupId>
<artifactId>plc4j-scraper</artifactId>
<version>0.7.0</version>
</dependency>
I have tried to change the version to an older one like 0.6.0 or 0.5.0 but the problem still persists.
If I use the modicon (Modbus TCP) I also get this exception after a little amount of time.
Anyone knows why is happening this error? Thanks in advance.
Edit: With the scraper version 0.8.0-SNAPSHOT I continue having this problem.
Edit2: This is my code, I think the problem can be that in my scraper I am opening a lot of connections and when it reaches 65526 messages it fails. But since all the processing is happenning inside the lambda function and I'm using a PooledPlcDriverManager, I think the scraper is using only one connection so I dont know where is the mistake.
try {
// Create a new PooledPlcDriverManager
PlcDriverManager S7_plcDriverManager = new PooledPlcDriverManager();
// Trigger Collector
TriggerCollector S7_triggerCollector = new TriggerCollectorImpl(S7_plcDriverManager);
// Messages counter
AtomicInteger messagesCounter = new AtomicInteger();
// Configure the scraper, by binding a Scraper Configuration, a ResultHandler and a TriggerCollector together
TriggeredScraperImpl S7_scraper = new TriggeredScraperImpl(S7_scraperConfig, (jobName, sourceName, results) -> {
LinkedList<Object> S7_results = new LinkedList<>();
messagesCounter.getAndIncrement();
S7_results.add(jobName);
S7_results.add(sourceName);
S7_results.add(results);
logger.info("Array: " + String.valueOf(S7_results));
logger.info("MESSAGE number: " + messagesCounter);
// Producer topics routing
String topic = "s7" + S7_results.get(1).toString().substring(S7_results.get(1).toString().indexOf("S7_SourcePLC") + 9 , S7_results.get(1).toString().length());
String key = parseKey_S7("s7");
String value = parseValue_S7(S7_results.getLast().toString(),S7_results.get(1).toString());
logger.info("------- PARSED VALUE -------------------------------- " + value);
// Create my own Kafka Producer
ProducerRecord<String, String> record = new ProducerRecord<String, String>(topic, key, value);
// Send Data to Kafka - asynchronous
producer.send(record, new Callback() {
public void onCompletion(RecordMetadata recordMetadata, Exception e) {
// executes every time a record is successfully sent or an exception is thrown
if (e == null) {
// the record was successfully sent
logger.info("Received new metadata. \n" +
"Topic:" + recordMetadata.topic() + "\n" +
"Partition: " + recordMetadata.partition() + "\n" +
"Offset: " + recordMetadata.offset() + "\n" +
"Timestamp: " + recordMetadata.timestamp());
} else {
logger.error("Error while producing", e);
}
}
});
}, S7_triggerCollector);
S7_scraper.start();
S7_triggerCollector.start();
} catch (ScraperException e) {
logger.error("Error starting the scraper (S7_scrapper)", e);
}
So in the end indeed it was the PLC that was simply hanging up the connection randomly. However the NiFi integration should have handled this situation more gracefully. I implemented a fix for this particular error ... could you please give version 0.8.0-SNAPSHOT a try (or use 0.8.0 if we happen to have released it already)
I have two dwg files: PID.dwg & 3D.dwg
The use case is to run a function on PID.dwg and then on 3D.dwg -- particularly in this order.
The commands used in SendCommand below are from a separate DLL file that I load using NETLOAD prior to this function's execution.
Dim app As AcadApplication = CType(Application.AcadApplication, AcadApplication)
' Ctype( Autodesk.AutoCAD.ApplicationServices.Application.AcadApplication,
' Autodesk.AutoCAD.Interop.AcadApplication )
If isPidAnd3dOpened() Then
' Activate PID document
app.ActiveDocument = acDocPid
'acDocPid.Activate()
acDocPid.SendCommand("DOSOMETHINGONPID" & vbCrLf)
' Activate 3D document
app.ActiveDocument = acDoc3d
'acDoc3d.Activate()
acDoc3d.SendCommand("DOSOMETHINGON3D" & vbCrLf)
End If
The function of "DOSOMETINGON3D" requires and input from the user using Editor.GetEntity.
However, when acDoc3d.SendCommand("DOSOMETHINGON3D" & vbCrLf) is executed, it does not pause to wait for user input.
What am I missing?
Probably You have to wait until the command DOSOMETHINGONPID is finished.
In ARX it would be something like this:
CString activeCMDName = _T("DOSOMETHINGONPID");
bool EOL = false;
while (!EOL)
{
CString cmds = Variable::Get(_T("CMDNAMES") );
if (cmds.Find( activeCMDName ) > 0 ) {
Command::Wait();
}
else {
EOL = true;
}
}
where
CString Variable::Get( CString name )
{
CString OutVal;
resbuf rb ;
acedGetVar(name, &rb);
OutVal.SetString(rb.resval.rstring);
acutDelString(rb.resval.rstring);
return OutVal ;
}
void Command::Wait()
{
ResBuf rb;
rb.Add(RTSTR , _T("\\"));
int ret = acedCmd(rb.GetFirst());
}
Sorry, I don't have this code in .net. Hope You will handle this.
First answer is correct, SendCommand cannot handle asynchronous commands. Here is a suggested solution in .Net:
//Create AutoCAD instance, then...
acadApp.ActiveDocument.SendCommand("(command \"NETLOAD\""+#"""C:\\acad\\networkdll\\SecondAssembly.dll"") ");
acadApp.ActiveDocument.SendCommand("#MYCOMMAND 0 ");
//Register EndCommand handler.
_DAcadApplicationEvents_EndCommandEventHandler handler = new
_DAcadApplicationEvents_EndCommandEventHandler(CommandEnded);
acadApp.EndCommand += handler;
waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset);
waitHandle.WaitOne();
acadApp.EndCommand -= handler;
//Close the startup drawing (this requires waiting # SendCommand) because
//Drawing will cause a COMException otherwise. 'Drawing is busy'
//Mostly likely since the ActiceDocument is the startup drawing.
Event Handler:
public void CommandEnded(string globalCommandName)
{
System.Windows.MessageBox.Show(globalCommandName + " just ended.");
waitHandle.Set();
}
I am using Selenium IDE to test a web based HR/SW system.
There is a screen that used to enter vacation for employees.
I am having nearly 3000 employee.
I built a test case that enter vacations for one employee using variables.
How can I repeat the test case for all 3000 employees without creating the test case 3000 times. It will take an impossible effort to do that. Note: Each employee is having different vacation data (Type, start date, End date)
Is there any way that I can use a file (Excel,....) that variable can use to read its data from?
Is there any solution for my case???
I will be very very grateful I any one could help me.
Thank you.
You could use an XML file as an input.
1) At first you have to add following user extensions:
sideflow.js - (http://51elliot.blogspot.com/2008/02/selenium-ide-goto.html - additionally this article explains how to add user extension files)
datadriven.js
include.js
At the moment I can't find links where I took the last two, therefore I will give their code in the end of my post. Code is taken from my working directory. You just put the code to correspondent files, then add files to SelemiunIDE user extension and use them.
2) Create an XML file test_data.xml:
<testdata>
<test employee="1" type="1" startDate="01.01.2013" endDate="01.02.2013" />
<test employee="2" type="1" startDate="01.02.2013" endDate="01.03.2013" />
<test employee="3" type="1" startDate="01.03.2013" endDate="01.04.2013" />
...
</testdata>
3) In your test case use code like this:
${DataPath} - full path to a directory with XML-files
<!--BEGIN LOOP-->
<tr>
<td>loadTestData</td>
<td>file://${DataDir}/test_data.xml</td>
<td></td>
</tr>
<tr>
<td>while</td>
<td>!testdata.EOF()</td>
<td></td>
</tr>
<tr>
<td>nextTestData</td>
<td></td>
<td></td>
</tr>
<tr>
<td>echo</td>
<td>employee=${employee} type=${type} ...</td>
<td></td>
</tr>
...
<!--END LOOP-->
<tr>
<td>endWhile</td>
<td></td>
<td></td>
</tr>
Used user extensions:
include.js
/**
* Original Developer: Jerry Qian(qqqiansjtucs#hotmail.com)
* Modified By: John Witchel (jwitchel#colevalleygroup.com)
* include extension for Selenium-IDE edition
* refer to includeCommand_2.1.3 for Selenium-Core edition
* #version 1.3
*
*/
function IDEIncludeCommand() {}
IDEIncludeCommand.LOG_PREFIX = "IDEIncludeCommand: ";
IDEIncludeCommand.BEGIN_TEMPLATE = "begin$Template$";
IDEIncludeCommand.END_TEMPLATE = "end$Template$";
IDEIncludeCommand.VERSION = "1.1";
IDEIncludeCommand.prototype.prepareTestCaseAsText = function(responseAsText, paramsArray) {
/**
* Prepare the HTML to be included in as text into the current testcase-HTML
* Strip all but the testrows (tr)
* Stripped will be:
* - whitespace (also new lines and tabs, so be careful wirt parameters relying on this),
* - comments (xml comments)
* Replace variable according to include-parameters
* note: the include-variables are replaced literally. selenium does it at execution time
* also note: all selenium-variables are available to the included commands, so mostly no include-parameters are necessary
*
* #param responseAsText table to be included as text (string)
* #return testRows array of tr elements (as string!) containing the commands to be included
*
* TODO:
* - selenium already can handle testcase-html. use selenium methods or functions instead
* - find better name for requester
*/
// removing new lines, carret return and tabs from response in order to work with regexp
var pageText = responseAsText.replace(/\r|\n|\t/g,"");
// remove comments
// begin comment, not a dash or if it's a dash it may not be followed by -> repeated, end comment
pageText = pageText.replace(/<!--(?:[^-]|-(?!->))*-->/g,"");
// find the content of the test table = <[spaces]table[char but not >]>....< /[spaces]table[chars but not >]>
var testText = pageText.match(/<\s*table[^>]*>(.*)<\/\s*table[^>]*>/i)[1];
// Replace <td></td> with <td> </td> for iE - credits Chris Astall
// rz: somehow in my IE 7 this is not needed but is not bad as well
testText = testText.replace(/<\s*td[^>]*>\s*<\s*\/td[^>]*>/ig,"<td></td>");// jq: no space
// replace vars with their values in testText
for ( var k = 0 ; k < paramsArray.length ; k++ ) {
var pair = paramsArray[k];
testText = testText.replace(pair[0],pair[1]);
}
// removes all < /tr>
// in order to split on < tr>
testText = testText.replace(/<\/\s*tr[^>]*>/ig,"");
// split on <tr>
var testRows = testText.split(/<\s*tr[^>]*>/i);
return testRows;
};
IDEIncludeCommand.prototype.getIncludeDocumentBySynchronRequest = function(includeUrl) {
/**
* Prepare and do the XMLHttp Request synchronous as selenium should not continue execution meanwhile
*
* note: the XMLHttp requester is returned (instead of e.g. its text) to let the caller decide to use xml or text
*
* selenium-dependency: uses extended String from htmlutils
*
* TODO use Ajax from prototype like this:
* var sjaxRequest = new Ajax.Request(url, {asynchronous:false});
* there is discussion about getting rid of prototype.js in developer forum.
* the ajax impl in xmlutils.js is not active by default in 0.8.2
*
* #param includeUrl URI to the include-document (document has to be from the same domain)
* #return XMLHttp requester after receiving the response
*/
var url = this.prepareUrl(includeUrl);
// the xml http requester to fetch the page to include
var requester = this.newXMLHttpRequest();
if (!requester) {
throw new Error("XMLHttp requester object not initialized");
}
requester.open("GET", url, false); // synchron mode ! (we don't want selenium to go ahead)
try {
requester.send(null);
} catch(e) {
throw new Error("Error while fetching url '" + url + "' details: " + e);
}
if ( requester.status != 200 && requester.status !== 0 ) {
throw new Error("Error while fetching " + url + " server response has status = " + requester.status + ", " + requester.statusText );
}
return requester;
};
IDEIncludeCommand.prototype.prepareUrl = function(includeUrl) {
/** Construct absolute URL to get include document
* using selenium-core handling of urls (see absolutify in htmlutils.js)
*/
var prepareUrl;
// htmlSuite mode of SRC? TODO is there a better way to decide whether in SRC mode?
if (window.location.href.indexOf("selenium-server") >= 0) {
LOG.debug(IDEIncludeCommand.LOG_PREFIX + "we seem to run in SRC, do we?");
preparedUrl = absolutify(includeUrl, htmlTestRunner.controlPanel.getTestSuiteName());
} else {
preparedUrl = absolutify(includeUrl, selenium.browserbot.baseUrl);
}
LOG.debug(IDEIncludeCommand.LOG_PREFIX + "using url to get include '" + preparedUrl + "'");
return preparedUrl;
};
IDEIncludeCommand.prototype.newXMLHttpRequest = function() {
// TODO should be replaced by impl. in prototype.js or xmlextras.js
// but: there is discussion of getting rid of prototype.js
// and: currently xmlextras.js is not activated in testrunner of 0.8.2 release
var requester = 0;
var exception = '';
// see http://developer.apple.com/internet/webcontent/xmlhttpreq.html
// changed order of native and activeX to get it working with native
// xmlhttp in IE 7. credits dhwang
try {
// for IE/ActiveX
if(window.ActiveXObject) {
try {
requester = new ActiveXObject("Msxml2.XMLHTTP");
}
catch(e) {
requester = new ActiveXObject("Microsoft.XMLHTTP");
}
}
// Native XMLHttp
else if(window.XMLHttpRequest) {
requester = new XMLHttpRequest();
}
}
catch(e) {
throw new Error("Your browser has to support XMLHttpRequest in order to use include \n" + e);
}
return requester;
};
IDEIncludeCommand.prototype.splitParamStrIntoVariables = function(paramString) {
/**
* Split include Parameters-String into an 2-dim array containing Variable-Name and -Value
*
* selenium-dependency: uses extended String from htmlutils
*
* TODO: write jsunit tests - this could be easy (if there were not the new RegExp)
*
* #param includeParameters string the parameters from include call
* #return new 2-dim Array containing regExpName (to find a matching variablename) and value to be substituted for
*/
var newParamsArray = new Array();
// paramString shall contains a list of var_name=value
var paramListPattern = /([^=,]+=[^=,]*,)*([^=,]+=[^=,]*)/;
if (! paramString || paramString === "") {
return newParamsArray;
} else if (paramString.match( paramListPattern )) {
// parse parameters to fill newParamsArray
var pairs = paramString.split(",");
for ( var i = 0 ; i < pairs.length ; i++ ) {
var pair = pairs[i];
var nameValue = pair.split("=");
//rz: use String.trim from htmlutils.js of selenium to get rid of whitespace in variable-name(s)
var trimmedNameValue = new String(nameValue[0]).trim();
// the pattern to substitute is ${var_name}
var regExpName = new RegExp("\\$\\{" + trimmedNameValue + "\\}", "g");
if (nameValue.length < 3) {
newParamsArray.push(new Array(regExpName,nameValue[1]));
} else {
var varValue = new String(nameValue[1]);
for (var j = 2; j < nameValue.length; j++) {
varValue=varValue.concat("="+nameValue[j]);
}
newParamsArray.push(new Array(regExpName,varValue));
}
}
} else {
throw new Error("Bad format for parameters list : '" + paramString + "'");
}
return newParamsArray;
};
IDEIncludeCommand.prototype.doInclude = function(locator, paramString) {
// Rewrite logic for Selenium IDE by Jerry Qian
var currentSelHtmlTestcase = testCase;
var includeCmdRow = testCase.debugContext.currentCommand();
if (!includeCmdRow) {
throw new Error("IDEIncludeCommand: failed to find include-row in source testtable");
}
var paramsArray = this.splitParamStrIntoVariables(paramString);
var inclDoc = this.getIncludeDocumentBySynchronRequest(locator);
// Get an array of commands from the include text with all whitespace stripped
var includedTestCaseHtml = this.prepareTestCaseAsText(inclDoc.responseText, paramsArray);
this.injectIncludeTestCommands(locator,includeCmdRow,includedTestCaseHtml);
};
IDEIncludeCommand.prototype.injectIncludeTestCommands = function(locator,includeCmdRow, testRows) {
// Rewrite logic for Selenium IDE by Jerry Qian
var newCommands = new Array();
// skip first element as it is empty or <tbody>
for (var i = 1 ; i < testRows.length; i++) {
if(i == 1){// add BEGIN-END block
var beginCommand = new Command(IDEIncludeCommand.BEGIN_TEMPLATE,locator,"");
newCommands.push(beginCommand);
}
var newText = testRows[i];
if(newText.match(/<\s*td.*colspan=.*>(.*)<\/\s*td[^>]*>/i)){//delete comment step
continue;
}
// removes all < /td>
// in order to split on <td>
newText = newText.replace(/<\/\s*td[^>]*>\s*<\/\s*tbody[^>]*>/ig,""); //remove </tbody>first
newText = newText.replace(/<\/\s*td[^>]*>/ig,"");
var newCols = newText.split(/<\s*td[^>]*>/i);
var new_cmd,new_target,new_value;
for (var j = 1 ; j < newCols.length; j++) {//skip 0
if(j == 1) {
new_cmd = newCols[j].replace(/\s/g,"");//trim \s
}else if(j == 2) {
new_target = newCols[j].replace(/\s+$/g,"");//trim end \s
}else if(j == 3) {
new_value = newCols[j].replace(/\s+$/g,"");//trim end \s
}
}
var newCommand = new Command(new_cmd,new_target,new_value);
newCommands.push(newCommand); //correct all steps
}
var endCommand = new Command(IDEIncludeCommand.END_TEMPLATE,locator,"");
newCommands.push(endCommand);//add BEGIN-END block
var cmsBefore = testCase.commands.slice(0,testCase.debugContext.debugIndex + 1);
var cmdsBehind = testCase.commands.slice(testCase.debugContext.debugIndex + 1, testCase.commands.length);
testCase.commands = cmsBefore.concat(newCommands).concat(cmdsBehind);//Injection
// Don't inject if it appears the injection has already been done
// (i.e., if the next command is the BEGIN).
if (testCase.commands.length <= testCase.debugContext.debugIndex+1
|| beginCommand.toString() != testCase.commands[testCase.debugContext.debugIndex+1].toString())
{
// The include command cannot be the last command in the TestCase, or else
// the de-injection code in doEnd$Template$ will cause an error. So we'll
// add a simple echo if it is the last.
if (testCase.commands.length == testCase.debugContext.debugIndex+1)
{
// Using concat instead of push so that we don't trigger the TestCase's set-modified flag.
testCase.commands = testCase.commands.concat(new Command("echo", "The include command cannot be the last line in a TestCase, so this command was added. It can be left in place or removed, as desired.", "The include command cannot be the last line in a TestCase, so this command was added. It can be left in place or removed, as desired."));
}
// This is original code.
var cmsBefore = testCase.commands.slice(0,testCase.debugContext.debugIndex + 1);
var cmdsBehind = testCase.commands.slice(testCase.debugContext.debugIndex + 1, testCase.commands.length);
testCase.commands = cmsBefore.concat(newCommands).concat(cmdsBehind);//Injection
}
};
Selenium.prototype.doInclude = function(locator, paramString) {
LOG.debug(IDEIncludeCommand.LOG_PREFIX + "Version " + IDEIncludeCommand.VERSION);
var ideIncludeCommand = new IDEIncludeCommand();
ideIncludeCommand.doInclude(locator, paramString);
// If goto scripts exist then reindex the labels. goto_sel_ide.js creates an array of labels when the
// script is initialized but an included file's labels are not part of that initial read, so this function
// re-initializes that array with the included files labels (if any). If goto_sel.ide.js is not included
// it's ignored.
try {
this.initialiseLabels();
}
catch (e) {
LOG.debug("Goto Script not used.");
}
};
// Array to hold the starting position of the Begin$Template$ marker. Pushing and popping the position onto an array
// allows us to correctly handle nested includes during clean up.
var beginTemplateIndex = new Array();
// Mark the beginning of the include
Selenium.prototype.doBegin$Template$ = function(locator){
LOG.info("Begin Template " + locator + " at position " + testCase.debugContext.debugIndex);
// Add the current position to the tail of the beginTemplateIndex
beginTemplateIndex.push(testCase.debugContext.debugIndex);
};
// Clean up everything between the closest Begin$Template$ and this $End$Template$, and pop the position off the array.
Selenium.prototype.doEnd$Template$ = function(locator){
// Remove the last Begin$Template$ from the tail of the beginTemplateIndex
var currentBeginTemplateIndex = beginTemplateIndex.pop();
LOG.info("End Template " + locator + " at position " + currentBeginTemplateIndex);
// Delete the commands that we injected in injectIncludeTestCommands.
testCase.commands =
testCase.commands.slice(0,currentBeginTemplateIndex).concat(
testCase.commands.slice(testCase.debugContext.debugIndex+1, testCase.commands.length));
// Set the current command to the next one after the injected block.
testCase.debugContext.debugIndex = currentBeginTemplateIndex-1;
//Must refresh to syncup UI
editor.view.refresh();
};
datadriven.js
/************************************ DATADRIVEN EXTENSION START ********************************************/
/*
NAME:
datadriven
Licensed under Apache License v2
http://www.apache.org/licenses/LICENSE-2.0
PURPOSE:
Basic data driven testing.
Full documentation at http://wiki.openqa.org/display/SEL/datadriven
EXAMPLE USE:
The structure of your data driven test case will be;
-------------------------------------------
COMMAND |TARGET |VALUE
-------------------------------------------
loadTestData |<file path> |
while |!testdata.EOF() |
testcommand1 | |
testcommand...| |
testcommandn | |
endWhile | |
-------------------------------------------
AUTHOR:
Jonathan McBrien
jonathan#mcbrien.org
2008-10-22: v0.1: Initial version.
2009-01-16: v0.2: Updated for Firefox 3.
xmlTestData.prototype.load now uses the include extension's getIncludeDocumentBySynchronRequest method for better portability.
(Why reinvent the wheel? :) - with appreciation to the include extension's authors.)
*/
XML.serialize = function(node) {
if (typeof XMLSerializer != "undefined")
return (new XMLSerializer()).serializeToString(node) ;
else if (node.xml) return node.xml;
else throw "XML.serialize is not supported or can't serialize " + node;
}
function xmlTestData() {
this.xmlDoc = null;
this.testdata = null;
this.index = null;
}
xmlTestData.prototype.load = function(xmlloc) {
loader = new IDEIncludeCommand();
var xmlHttpReq = loader.getIncludeDocumentBySynchronRequest(xmlloc);
this.xmlDoc = xmlHttpReq.responseXML;
this.index = 0;
this.testdata = this.xmlDoc.getElementsByTagName("test");
if (this.testdata == null || this.testdata.length == 0) {
throw new Error("Test data couldn't be loaded or test data was empty.");
}
}
xmlTestData.prototype.EOF = function() {
if (this.index != null && this.index < this.testdata.length) return false;
return true;
}
xmlTestData.prototype.more = function() {
return !this.EOF();
}
xmlTestData.prototype.next = function() {
if (this.EOF()) {
LOG.error("No test data.");
return;
}
LOG.info(XML.serialize(this.testdata[this.index])); // Log should anything go wrong while testing with this data.
if (this.testdata[this.index].attributes.length != this.testdata[0].attributes.length) {
LOG.error("Inconsistent attribute length in test data.");
return;
}
for (i=0; i<this.testdata[this.index].attributes.length; i++){
if (null == this.testdata[0].getAttribute(this.testdata[this.index].attributes[i].nodeName)) {
LOG.error("Inconsistent attribute names in test data.");
return;
}
selenium.doStore(this.testdata[this.index].attributes[i].nodeValue, this.testdata[this.index].attributes[i].nodeName);
}
this.index++;
}
Selenium.prototype.testdata = null;
Selenium.prototype.doLoadTestData = function(xmlloc) {
testdata = new xmlTestData();
testdata.load(xmlloc);
};
Selenium.prototype.doNextTestData = function() {
testdata.next();
};
/************************************ DATADRIVEN EXTENSION END **********************************************/
Current solution is a SelBlocks component which allows you to do cycles according to the dataset in XML
ForXML | XMLFileName.XML
... test case steps
EndForXML
The XML should have specific structure
<testdata>
<vars storedVariable1="xxxxx" storedVariable2="yyyyy" .. storedVariableN="zzzzz" />
.. other record(s)
</testdata>
Each stored variable vill be available in test case as ${storedVariableN}.
You can produce XML by MS Excel or LibreOffice using Formulas like this one and copy it to whole table:
="<vars "&
" "&$A$1&"="""&A2&""" "&
" "&$B$1&"="""&B2&""" "&
..
" "&$X$1&"="""&X2&""" "&
"/>")
XML can be easily copypasted after each change of the dataset.
Selblocks contains the while, datadriven, goto, loop and other extensions mentioned in previous answers. You can use other functionalities of the Selblocks as conditional jumps, conditions, catch-try blocks, functions, etc. See full reference here: http://refactoror.wikia.com/wiki/Selblocks_Reference
Beware with new Selenium 3 release and Sel Core absence it is not guaranteed, that tests with Selblock addon will work in the future versions of the firefox.
You can also check this very nice blog article:
http://seleniumworks.blogspot.com/2014/01/selenium-ide-data-driven.html
This gives an explanation on how to use the needed plugins and where to download them from. It worked perfectly for me.
This answer pretty much has the same approach as the one provided by #Yevgen Ulyanenkov as I used his answer in order to find the above article. But has some more googling to it that hopefully will be helpful to someone.
I think you need to use loop I don't see your code so just check this one for selenium-ide loop If you have any more problem if so comment my answer. I can't comment into your question because reputation is not enough so. If possible please add your code into your question.
I am learning to use the Rx extensions for a Silverlight 4 app I am working on. I created a sample app to nail down the process and I cannot get it to return anything.
Here is the main code:
private IObservable<Location> GetGPSCoordinates(string Address1)
{
var gsc = new GeocodeServiceClient("BasicHttpBinding_IGeocodeService") as IGeocodeService;
Location returnLocation = new Location();
GeocodeResponse gcResp = new GeocodeResponse();
GeocodeRequest gcr = new GeocodeRequest();
gcr.Credentials = new Credentials();
gcr.Credentials.ApplicationId = APP_ID2;
gcr.Query = Address1;
var myFunc = Observable.FromAsyncPattern<GeocodeRequest, GeocodeResponse>(gsc.BeginGeocode, gsc.EndGeocode);
gcResp = myFunc(gcr) as GeocodeResponse;
if (gcResp.Results.Count > 0 && gcResp.Results[0].Locations.Count > 0)
{
returnLocation = gcResp.Results[0].Locations[0];
}
return returnLocation as IObservable<Location>;
}
gcResp comes back as null. Any thoughts or suggestions would be greatly appreciated.
The observable source you are subscribing to is asynchronous, so you can't access the result immediately after subscribing. You need to access the result in the subscription.
Better yet, don't subscribe at all and simply compose the response:
private IObservable<Location> GetGPSCoordinates(string Address1)
{
IGeocodeService gsc =
new GeocodeServiceClient("BasicHttpBinding_IGeocodeService");
Location returnLocation = new Location();
GeocodeResponse gcResp = new GeocodeResponse();
GeocodeRequest gcr = new GeocodeRequest();
gcr.Credentials = new Credentials();
gcr.Credentials.ApplicationId = APP_ID2;
gcr.Query = Address1;
var factory = Observable.FromAsyncPattern<GeocodeRequest, GeocodeResponse>(
gsc.BeginGeocode, gsc.EndGeocode);
return factory(gcr)
.Where(response => response.Results.Count > 0 &&
response.Results[0].Locations.Count > 0)
.Select(response => response.Results[0].Locations[0]);
}
If you only need the first valid value (the location of the address is unlikely to change), then add a .Take(1) between the Where and Select.
Edit: If you want to specifically handle the address not being found, you can either return results and have the consumer deal with it or you can return an Exception and provide an OnError handler when subscribing. If you're thinking of doing the latter, you would use SelectMany:
return factory(gcr)
.SelectMany(response => (response.Results.Count > 0 &&
response.Results[0].Locations.Count > 0)
? Observable.Return(response.Results[0].Locations[0])
: Observable.Throw<Location>(new AddressNotFoundException())
);
If you expand out the type of myFunc you'll see that it is Func<GeocodeRequest, IObservable<GeocodeResponse>>.
Func<GeocodeRequest, IObservable<GeocodeResponse>> myFunc =
Observable.FromAsyncPattern<GeocodeRequest, GeocodeResponse>
(gsc.BeginGeocode, gsc.EndGeocode);
So when you call myFunc(gcr) you have an IObservable<GeocodeResponse> and not a GeocodeResponse. Your code myFunc(gcr) as GeocodeResponse returns null because the cast is invalid.
What you need to do is either get the last value of the observable or just do a subscribe. Calling .Last() will block. If you call .Subscribe(...) your response will come thru on the call back thread.
Try this:
gcResp = myFunc(gcr).Last();
Let me know how you go.
Richard (and others),
So I have the code returning the location and I have the calling code subscribing. Here is (hopefully) the final issue. When I call GetGPSCoordinates, the next statement gets executed immediately without waiting for the subscribe to finish. Here's an example in a button OnClick event handler.
Location newLoc = new Location();
GetGPSCoordinates(this.Input.Text).ObserveOnDispatcher().Subscribe(x =>
{
if (x.Results.Count > 0 && x.Results[0].Locations.Count > 0)
{
newLoc = x.Results[0].Locations[0];
Output.Text = "Latitude: " + newLoc.Latitude.ToString() +
", Longtude: " + newLoc.Longitude.ToString();
}
else
{
Output.Text = "Invalid address";
}
});
Output.Text = " Outside of subscribe --- Latitude: " + newLoc.Latitude.ToString() +
", Longtude: " + newLoc.Longitude.ToString();
The Output.Text assignment that takes place outside of Subscribe executes before the Subscribe has finished and displays zeros and then the one inside the subscribe displays the new location info.
The purpose of this process is to get location info that will then be saved in a database record and I am processing multiple addresses sequentially in a Foreach loop. I chose Rx Extensions as a solution to avoid the problem of the async callback as a coding trap. But it seems I have exchanged one trap for another.
Thoughts, comments, suggestions?
Is there any way to force Hudson to give me more detailed test results - e.g. I'm comparing two strings and I want to know where they differ.
Is there any way to do this?
Thank you for help.
You should not hope Hudson give the detail information, it just shows the testing messages generated by junit.
You could show the expected string and actual string when failing asserting equals between those two strings.
For example,
protected void compareFiles(File newFile, String referenceLocation, boolean lineNumberMatters) {
BufferedReader reader = null;
BufferedReader referenceReader = null;
List<String> expectedLines = new ArrayList<String>();
try {
referenceReader = new BufferedReader(new InputStreamReader(FileLocator.openStream(Activator.getDefault().getBundle(), new Path("data/regression/" + referenceLocation), false))); //$NON-NLS-1$
expectedLines = getLinesFromReader(referenceReader);
} catch (Exception e) {
assertFalse("Exception occured during reading reference data: " + e, true); //$NON-NLS-1$
}
List<String>foundLines = new ArrayList<String>();
try {
reader = new BufferedReader(new FileReader(newFile));
foundLines = getLinesFromReader(reader);
} catch (Exception e) {
assertFalse("Exception occured during reading file: " + e, true); //$NON-NLS-1$
}
boolean throwException = expectedLines.size() != foundLines.size();
if (throwException) {
StringBuffer buffer = new StringBuffer("\n" + newFile.toString()); //$NON-NLS-1$
for (String line: foundLines)
buffer.append(line + "\n"); //$NON-NLS-1$
assertEquals("The number of lines in the reference(" + referenceLocation + ") and new output(" + newFile.getAbsolutePath()+ ") did not match!" + buffer, expectedLines.size(), foundLines.size()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
if (!lineNumberMatters) {
Collections.sort(expectedLines);
Collections.sort(foundLines);
}
/** Either the line matches character by character or it matches regex-wise, in that order */
for (int i=0;i<expectedLines.size(); i++)
assertTrue("Found errors in file (" + newFile + ")! " + foundLines.get(i) + " vs. " + expectedLines.get(i), foundLines.get(i).equals(expectedLines.get(i)) || foundLines.get(i).matches(expectedLines.get(i))); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
Hudson supports JUnit directly. On your job configuration page, near the end, should be an option to "Publish JUnit test results report".
I'm not too familiar with JUnit itself, but I guess it produces (or has the ability to produce) and put results in an xml file. You just need to put the path of to the xml file (relative to the workspace) in the text box.
Once you do that, and create a build, you'll have a detailed report on your project page. You should then be able to click your way through the results for each test.