Null Pointer Exception on testng datprovider - xml-parsing

I am running in a strange problem. Let me explain:
I am passing set of input data from xml and then using JAXB to parse xml. This java object is then passed to my test method using testng dataprovider.
Here are some related code:
Testdata xml:
<TestData>
<TestDetails>
<testcasename>itemStatusTest</testcasename>
<testcasedetails>App in SUPPRESSED Status</testcasedetails>
<appid>28371</appid>
<status>SUPPRESSED</status>
<marketplace />
</TestDetails>
<TestDetails>
<testcasename>itemStatusTest</testcasename>
<testcasedetails>App in REVIEW Status</testcasedetails>
<appid>22559</appid>
<status>REVIEW</status>
<marketplace />
</TestDetails>
</TestData>
Method which returns object:
private static Object[][] generateTestData(String dataProvider,TestCaseName tcName) throws Exception {
Object[][] obj = null;
try {
JAXBContext jaxbContext = JAXBContext.newInstance(TestData.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
TestData testData = (TestData) jaxbUnmarshaller
.unmarshal(new FileInputStream(new File(dataProvider)
.getAbsoluteFile()));
List<TestDetails> testcaseList = testData.getTestDetails();
obj = new Object[testcaseList.size()][];
for (int i = 0; i < testcaseList.size(); i++) {
if (testcaseList
.get(i)
.getTestcasename()
.equalsIgnoreCase(tcName.testCaseName()))
obj[i] = new Object[] { testcaseList.get(i) };
}
} catch (JAXBException e) {
e.getMessage();
return null;
}
return obj;
}
and my dataprovider:
#DataProvider(parallel = true, name = "TestData")
public Object[][] TestData() {
try {
Object obj[][]= IngestionTestHelper
.generateTestDataForItemStatus(dataProvider);
Reporter.log("Size "+obj.length, true);
return obj;
} catch (Exception e) {
Reporter.log(
"Either XML input is in wrong format or XML is not parsed correctly",
true);
return null;
}
}
Till now everything works like a charm and I am not seeing any issue.
Now i am writing another test method for another test-case. For that I have added following in my exisitng xml like this:
<TestDetails>
<testcasename>itemWorkflowTest</testcasename>
<testcasedetails>Validate workflow for iap</testcasedetails>
<appid>26120</appid>
<status />
<marketplace />
</TestDetails>
Now once i have added this in my existing xml my existing test method is not working. When running I am getting following exception:
java.lang.NullPointerException
at org.testng.internal.Invoker.injectParameters(Invoker.java:1333)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1203)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:127)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:111)
at org.testng.TestRunner.privateRun(TestRunner.java:767)
at org.testng.TestRunner.run(TestRunner.java:617)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:334)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:329)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:291)
at org.testng.SuiteRunner.run(SuiteRunner.java:240)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1197)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1122)
at org.testng.TestNG.run(TestNG.java:1030)
at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:111)
at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:204)
at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:175)
If i remove the newly added block in xml it starts working.
Please someone help!!!

Well, based on the code, and if I understood correctly :)
When you add the third item the name is different,
You have initialized the Object array with the size of the total number of elements,
obj = new Object[testcaseList.size()][];
But you are adding to the array selectively based on name, so though the init has been done for 3 objects, the data is available only for 2 - this may be causing the NPE..
List<TestDetails> testcaseList = testData.getTestDetails();
obj = new Object[testcaseList.size()][];
for (int i = 0; i < testcaseList.size(); i++) {
if (testcaseList
.get(i)
.getTestcasename()
.equalsIgnoreCase(tcName.testCaseName()))
obj[i] = new Object[] { testcaseList.get(i) };
}

Related

sqljocky query does not have a method 'then' (dart database access)

I'm trying to code sql access to a database using sqljocky in Dart. As I want to make some computation with the result returned by my database Handler, the method return a Future.
But when I try to run it, I'm getting the following error:
Uncaught Error: The null object does not have a method 'then'`
I've ran the debugger and found that this error raise on:
db.query('select * from user where email="$email"').then(...)
but the catchError clause doesn't fire.
My handler method is:
// db is a ConnectionPool
Future<Map<String,String>> queryUser(String email){
print(email);
db.query('select * from user where email="${email}"').then((result) { // here raise the error
Map<String,String> results = new Map<String,String>();
result.forEach((row){
results['status'] = '200';
results['ID'] = row[0];
results['Image'] = row[1];
results['Name'] = row[2];
results['Email'] = row[3];
results['Password'] = row[4];
});
return results;
}).catchError((error){
Map<String,String> results = new Map<String,String>();
results['status'] = '500';
return results;
});
}
And the method that call this handler is:
List getUser(String email) {
Future<Map<String,String>> result = dbhandler.queryUser(email);
result.then((Map<String,String> result) {
String statuscode = result['status'];
result.remove('status');
String json = JSON.encode(result);
List pair = new List();
pair.add(statuscode);
pair.add(json);
return pair;
});
If I run the query directly in phpmyadmin, it return correct data, so it is correct.
Can someone give me a hint about how to solve it?
The queryUser() method will always return null, as there is no return statement. In the next release of Dart there will be a static hint warning for this, but at the moment there is none.
Perhaps the code below is what you meant to do. Note the initial return statement before db.query(), and the extra result.toList() call. I haven't tested this, so there's probably a typo or two.
Future<Map<String,String>> queryUser(String email){
print(email);
return db.query('select * from user where email="${email}"')
.then((result) => result.toList())
.then((rows) {
var row = rows.single;
Map<String,String> results = new Map<String,String>();
results['status'] = '200';
results['ID'] = row[0];
results['Image'] = row[1];
results['Name'] = row[2];
results['Email'] = row[3];
results['Password'] = row[4];
return results;
}).catchError((error){
Map<String,String> results = new Map<String,String>();
results['status'] = '500';
return results;
});
}
You can also make this a bit cuter using map literals:
Future<Map<String,String>> queryUser(String email){
return db.query('select * from user where email="${email}"')
.then((result) => result.toList())
.then((rows) => <String, String> {
'status': '200',
'ID': rows.single[0],
'Image': rows.single[1],
'Name': rows.single[2],
'Email': rows.single[3],
'Password': rows.single[4] })
.catchError((error) => <String, String> {'status': '500'});
}
Finally I found the answer using Completer to control the Future object, but the real problem was, as Greg Lowe said, that my methods doesn't return anything as they come to end before the then clause.
Using completer, I've made my query method as:
Future<Map<String,String>> queryUser(String email){
Completer c = new Completer();
db.query('select * from user where email="$email"').then((result) {
Map<String,String> results = new Map<String,String>();
result.forEach((row){
results['status'] = '200';
results['ID'] = row[0].toString();
results['Image'] = row[1];
results['Name'] = row[2];
results['Email'] = row[3];
results['Password'] = row[4];
}).then((onValue){
c.complete(results);
});
}).catchError((error){
Map<String,String> results = new Map<String,String>();
results['status'] = '500';
c.completeError((e) => print("error en queryUser"));
});
return c.future;
}
I also solved an error when using the foreach method, at first I supposed it return nothing, but after that, I noticed that it return a Future, so I added a then clause.
And my getUser method:
Future<List> getUser(String email) {
Completer c = new Completer();
Future<Map<String,String>> result = dbhandler.queryUser(email);
result.then((Map<String,String> result) {
String statuscode = result['status'];
result.remove('status');
String json = JSON.encode(result);
List pair = new List();
pair.add(statuscode);
pair.add(json);
c.complete(pair);
});
return c.future;
}
After those changes, everything works right

How to parse soapfault's detail?

I am trying to get the values inside this soap fault's "detail", but I haven't found any ways of doing so.
The response from the server:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>SOAP-ENV:Client</faultcode>
<faultstring>Many Errors</faultstring>
<detail>
<error_id>2</error_id>
<errors>
<error>
<error_id>1</error_id>
<error_description>Unknown Error</error_description>
</error>
<error>
<error_id>5</error_id>
<error_description>Not Authorized</error_description>
</error>
<error>
<error_id>9</error_id>
<error_description>Password should be at least 6 characters including one letter and one number</error_description>
</error>
</errors>
</detail>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
I need to get the error_ids along with their respective error_descriptions. So far I've only managed to get the detail via kSOAP with the following way:
if (envelope.bodyIn instanceof SoapObject) {
return envelope.bodyIn.toString();
} else if (envelope.bodyIn instanceof SoapFault) {
SoapFault e = (SoapFault) envelope.bodyIn;
Node details = ((SoapFault) envelope.bodyIn).detail;
}
but I haven't managed to get a single value I need when I try to "navigate" through it.
Any help is greatly appreciated. I have found little to non information about handling soap faults with ksoap2 online...
The following code handles better
Iterator it = soapFaultClientException.getSoapFault().getFaultDetail().getDetailEntries();
while (it.hasNext())
{
Source errSource = it.next().getSource();
#SuppressWarnings("unchecked")
JAXBElement errJaxb = (JAXBElement) springWebServiceTemplate.getUnmarshaller().unmarshal(errSource);
ServerCustomizedError err = errJaxb.getValue();
....
}
Figured it out after all. Here is the way to do it:
Node details = ((SoapFault) envelope.bodyIn).detail;
Element detEle = details.getElement(NAMESPACE, "detail");
List<Error> errorList = new ArrayList<NewConnector.Error>();
Element idEle = detEle.getElement(NAMESPACE, "error_id");
str.append("id: " + idEle.getText(0));
str.append("\n");
Integer id = Integer.valueOf(idEle.getText(0));
if (id == 2) {
// many errors
Element errors = detEle.getElement(NAMESPACE, "errors");
int errorChildCount = errors.getChildCount();
for (int i = 0; i < errorChildCount; i++) {
Object innerError = errors.getChild(i);
if (innerError instanceof Element) {
Element error_id = ((Element) innerError).getElement(
NAMESPACE, "error_id");
Element error_descrion = ((Element) innerError)
.getElement(NAMESPACE, "error_description");
Error singleError = new Error(Integer.valueOf(error_id
.getText(0)), error_descrion.getText(0));
errorList.add(singleError);
str.append(singleError.toString() + "\n");
}
}
str.append("Found " + errorList.size() + " errors.\n");
str.append("errorscount:" + errors.getChildCount());
The code obviously needs improvements, but it's just a showcase of how to get each value. Cheers
I use the following method:
/**
* Method to retrieve the errorMessage from the given SoapFault.
* #param soapFault
* #return String representing the errorMessage found in the given SoapFault.
*/
private static String getSoapErrorMessage (SoapFault soapFault) {
String errorMessage;
try {
Node detailNode = soapFault.detail;
Element faultDetailElement = (Element)detailNode.getElement(0).getChild(1);
Element errorMessageElement = (Element)faultDetailElement.getChild(0);
errorMessage = errorMessageElement.getText(0);
}
catch (Exception e) {
e.printStackTrace();
errorMessage = "Could not determine soap error.";
}
return errorMessage;
}

Writing a list of strings to a file

From the API page, I gather there's no function for what I'm trying to do. I want to read text from a file storing it as a list of strings, manipulate the text, and save the file. The first part is easy using the function:
abstract List<String> readAsLinesSync([Encoding encoding = Encoding.UTF_8])
However, there is no function that let's me write the contents of the list directly to the file e.g.
abstract void writeAsLinesSync(List<String> contents, [Encoding encoding = Encoding.UTF_8, FileMode mode = FileMode.WRITE])
Instead, I've been using:
abstract void writeAsStringSync(String contents, [Encoding encoding = Encoding.UTF_8, FileMode mode = FileMode.WRITE])
by reducing the list to a single string. I'm sure I could also use a for loop and feed to a stream line by line. I was wondering two things:
Is there a way to just hand the file a list of strings for writing?
Why is there a readAsLinesSync but no writeAsLinesSync? Is this an oversight or a design decision?
Thanks
I just made my own export class that handles writes to a file or for sending the data to a websocket.
Usage:
exportToWeb(mapOrList, 'local', 8080);
exportToFile(mapOrList, 'local/data/data.txt');
Class:
//Save data to a file.
void exportToFile(var data, String filename) =>
new _Export(data).toFile(filename);
//Send data to a websocket.
void exportToWeb(var data, String host, int port) =>
new _Export(data).toWeb(host, port);
class _Export {
HashMap mapData;
List listData;
bool isMap = false;
bool isComplex = false;
_Export(var data) {
// Check is input is List of Map data structure.
if (data.runtimeType == HashMap) {
isMap = true;
mapData = data;
} else if (data.runtimeType == List) {
listData = data;
if (data.every((element) => element is Complex)) {
isComplex = true;
}
} else {
throw new ArgumentError("input data is not valid.");
}
}
// Save to a file using an IOSink. Handles Map, List and List<Complex>.
void toFile(String filename) {
List<String> tokens = filename.split(new RegExp(r'\.(?=[^.]+$)'));
if (tokens.length == 1) tokens.add('txt');
if (isMap) {
mapData.forEach((k, v) {
File fileHandle = new File('${tokens[0]}_k$k.${tokens[1]}');
IOSink dataFile = fileHandle.openWrite();
for (var i = 0; i < mapData[k].length; i++) {
dataFile.write('${mapData[k][i].real}\t'
'${mapData[k][i].imag}\n');
}
dataFile.close();
});
} else {
File fileHandle = new File('${tokens[0]}_data.${tokens[1]}');
IOSink dataFile = fileHandle.openWrite();
if (isComplex) {
for (var i = 0; i < listData.length; i++) {
listData[i] = listData[i].cround2;
dataFile.write("${listData[i].real}\t${listData[i].imag}\n");
}
} else {
for (var i = 0; i < listData.length; i++) {
dataFile.write('${listData[i]}\n');
}
}
dataFile.close();
}
}
// Set up a websocket to send data to a client.
void toWeb(String host, int port) {
//connect with ws://localhost:8080/ws
//for echo - http://www.websocket.org/echo.html
if (host == 'local') host = '127.0.0.1';
HttpServer.bind(host, port).then((server) {
server.transform(new WebSocketTransformer()).listen((WebSocket webSocket) {
webSocket.listen((message) {
var msg = json.parse(message);
print("Received the following message: \n"
"${msg["request"]}\n${msg["date"]}");
if (isMap) {
webSocket.send(json.stringify(mapData));
} else {
if (isComplex) {
List real = new List(listData.length);
List imag = new List(listData.length);
for (var i = 0; i < listData.length; i++) {
listData[i] = listData[i].cround2;
real[i] = listData[i].real;
imag[i] = listData[i].imag;
}
webSocket.send(json.stringify({"real": real, "imag": imag}));
} else {
webSocket.send(json.stringify({"real": listData, "imag": null}));
}
}
},
onDone: () {
print('Connection closed by client: Status - ${webSocket.closeCode}'
' : Reason - ${webSocket.closeReason}');
server.close();
});
});
});
}
}
I asked Mads Agers about this. He works on the io module. He said that he decided not to add writeAsLines because he didn't find it useful. For one it is trivial to write the for loop and the other thing is that you have to parameterize it which the kind of line separator that you want to use. He said he can add it if there is a strong feeling that it would be valuable. He didn't immediately see a lot of value in it.

Entity Framework Newbie - Save to DB

I have 3 joined tables; ValidationRun has many Result which has many Error
The following code succeeds in saving to the Result and Error tables but not the ValidationRun.
Can you see the problem please?
private void WriteResultsToDB(SqlDataReader dr, XMLValidator validator)
{
using (var context = new ValidationResultsEntities())
{
var run = new ValidationRun { DateTime = DateTime.Now, XSDPath = this.txtXsd.Text };
//loop through table containing the processed XML
while (dr.Read())
{
var result = new Result
{
AddedDateTime = (DateTime)dr["Added"],
CustomerAcc = (string)dr["CustomerAcc"],
CustomerRef = (string)dr["CustomerRef"]
};
if (this.rdoRequest.Checked)
{
result.XMLMsg = (string)dr["RequestMSG"];
}
else
{
result.XMLMsg = (string)dr["ReplyMSG"];
}
if (validator.Validate(result.XMLMsg))
{
foreach (string error in validator.Errors)
{
result.Errors.Add(new Error { ErrorDescription = error });
}
}
else
{
//validator caught an error
result.Errors.Add(new Error { ErrorDescription = "XML could not be parsed" });
}
if (result.Errors.Count == 0) result.ValidFile = true; else result.ValidFile = false;
context.AddToResults(result);
context.SaveChanges();
}
}
You don't appear to be adding the run to any part of the context. If it were referenced by the result you are adding, perhaps, the change tracker would know it was supposed to be saved, but as it is written it is just some orphaned object that doesn't get attached anywhere.

displaying errors in grails without refreshing the page

I have a page with dynamic list boxes(selecting value from the first list populates the values in the second list box).
The validation errors for the list boxes are working fine, but while displaying the error messages the page is getting refreshed and the selected values are been set to initial status(need to select the values again in the list boxes)
The page is designed to add any number of list boxes using ajax calls, so adding and selecting the values again is going to be a rework.
Could you help me in displaying the validation errors and keeping the selected values as they are(previously I faced a similar situation which was resolved by replacing local variables of preprocess and postprocess with a global variable, this time no luck with that approach)
Any hints/help would be great
static constraints = {
deviceMapping(
validator: {val, obj ->
Properties dm = (Properties) val;
def deviceCheck = [:];
if (obj.customErrorMessage == null) {
for (def device : dm) {
if (device.key == null || "null".equalsIgnoreCase(device.key)) {
return ["notSelected"];
}
deviceCheck.put(device.key, "");
}
if (deviceCheck.size() != obj.properties["numberOfDevices"]) {
return ["multipleDevicesError"];
}
}
}
)
customErrorMessage (
validator: {
if ("sameDeviceMultipleTimes".equals(it)) {
return ['sameDeviceMultipleTimes']
}
}
)
}
public LinkedHashMap<String, Object> preProcess(sessionObject, params, request) {
Submission submission = (Submission) sessionObject;
def selectedFileName = sessionObject.fileName;
logger.debug("submission.deviceMapping :"+submission.deviceMapping)
try {
Customer customer = Customer.get(submission.customerId);
OperatingSystem operatingSystem = OperatingSystem.get(submission.operatingSystemId)
def ftpClientService = new FtpClientService();
def files = ftpClientService.listFilesInZip(customer.ftpUser, customer.ftpPassword, customer.ftpHost, customer.ftpToPackageDirectory, selectedFileName, operatingSystem, customer.ftpCustomerTempDirectory);
def terminalService = new TerminalService();
OperatingSystem os = OperatingSystem.get(submission.getOperatingSystemId());
def manufacturers = terminalService.getAllDeviceManufacturersForType(os.getType());
logger.debug("manufacturers after os type :"+manufacturers)
logger.debug("files in preprocess :"+files)
def devicesForFiles = [:]
files.each { file ->
def devicesForThisFile = [];
submission.deviceMapping.each { device ->
if (device.value == file.fileName) {
String manufacturer = terminalService.getManufacturerFromDevice("${device.key}");
def devicesForManufacturer = terminalService.getDevicesForManufacturerAndType(manufacturer, os.getType());
devicesForThisFile.push([device:device.key, manufacturer: manufacturer, devicesForManufacturer: devicesForManufacturer]);
}
}
devicesForFiles.put(file.fileName,devicesForThisFile);
}
logger.debug("devicesForFiles :"+devicesForFiles)
return [command: this, devicesForFiles: devicesForFiles, files: files, manufacturers: manufacturers];
} catch (Exception e) {
logger.warn("FTP threw exception");
logger.error("Exception", e);
this.errors.reject("mapGameToDeviceCommand.ftp.connectionTimeOut","A temporary FTP error occurred");
return [command: this];
}
}
public LinkedHashMap<String, Object> postProcess(sessionObject, params, request) {
Submission submission = (Submission) sessionObject;
Properties devices = params.devices;
Properties files = params.files;
mapping = devices.inject( [:] ) { map, dev ->
// Get the first part of the version (up to the first dot)
def v = dev.key.split( /\./ )[ 0 ]
map << [ (dev.value): files[ v ] ]
}
deviceMapping = new Properties();
params.files.eachWithIndex { file, i ->
def device = devices["${file.key}"];
if (deviceMapping.containsKey("${device}")) {
this.errors.reject("You cannot use the same device more than once");
return [];
//customErrorMessage = "sameDeviceMultipleTimes";
}
deviceMapping.put("${device}", "${file.value}");
}
if (params.devices != null) {
this.numberOfDevices = params.devices.size(); //Used for the custom validator later on
} else {
this.numberOfDevices = 0;
}
//logger.debug("device mapping :"+deviceMapping);
submission.deviceMapping = mapping;
return [command: this, deviceMapping: mapping, devicesForFiles: devicesForFiles ];
}
}
The problem is in your gsp page. Be sure that all field are initialised with a value
<g:text value="${objectInstance.fieldname}" ... />
Also the way it is selecting values is through id, so be sure to set it as well:
<g:text value="${objectInstance.fieldname}" id=${device.manufacturer.id} ... />

Resources