Spock Testing a POST Service in Grails - grails

EDIT 2: Figured out how to pass an integer, however my now my test is failing because the value coming back is empty but the render is the correct value on the web page.
EDIT: I've figured out how to pass values by POST using the request.method, however i now can't figure out how to pass an int into the controller using request, as each addParameter expects a string.
I have a convert application in grails, where both the binary and hex service take a parameter via post before converting it to either binary or hex and returning the result. I'm now writing some Spock tests to test each service however i can't seem to figure out how to test the service if the parameter is required to be sent via POST rather than GET.
Binary Convert Service:
def binary() {
if (request.method == 'POST') {
if (session.user) {
Integer number = params.getInt('number')
String binary = Integer.toBinaryString(number)
def r = new Results()
r.customerID = session["id"]
r.username = session["username"]
r.ConvertService = "binary"
r.number = number
r.result = binary
r.date = new Date()
r.time = new Timestamp(System.currentTimeMillis())
if(r.save()) {
render binary
} else {
render r.getErrors()
}
} else {
redirect(controller: 'main')
}
} else {
response.sendError(405)
}
}
Spock test:
void "Binary Service should return 1100"() {
given:
def convert = new ConvertController()
when:
def result = convert.binary(12)
then:
result == 1100
}
This is what my test returns right now:
groovy.lang.MissingMethodException: No signature of method: eadassignment.ConvertController.binary() is applicable for argument types: (java.lang.Integer) values: [12]
Possible solutions: binary(), any(), <init>(), index(), every(), find()
at org.codehaus.groovy.grails.plugins.web.api.ControllerTagLibraryApi.methodMissing(ControllerTagLibraryApi.java:97)
at eadassignment.ConvertControllerSpec.Binary Service should return 1100(ConvertControllerSpec.groovy:22)

Figured out all my problems. Last one was because the function checked if a valid user existed which the test was failing for obvious reasons.

Related

Grails createCriteria not returning any results

I'm trying to use the createCriteria in a grails application to return some rows from a DB. I'm not getting any results.
def query = {
ilike('fullName','%${params.term}%')
projections {
property('id')
property('fullName')
}
}
def plist = Patient.createCriteria().list(query)
def patientSelectList = []
plist.each {
def pMap = [:]
pMap.put("id", it[0])
pMap.put("label", it[1])
pMap.put("value", it[1])
patientSelectList.add(pMap)
}
the fields i'm looking for exist as the following snippet returns results but is very slow.
def patientList = Patient.getAll()
def patientSelectList = []
patientList.each { patient ->
if (patient.fullName.toLowerCase().contains(params.term.toLowerCase()) ) {
def pMap = [:]
pMap.put("id", patient.id)
pMap.put("label", patient.fullName)
patientSelectList.add(pMap)
}
}
return patientSelectList
thanks for anyhelp
I had my Db fields encryted with jasypt. Removing the encryption on the field I needed to query fixed the issue!
You're using a String rather than a GString in the ilike() parameter, so params.term is not being evaluated. To use a GString, use double-quotes instead.
ilike('fullName',"%${params.term}%")
Also make sure % is an appropriate wildcard character for your database (it probably is).

Grails findBy multiple columns Ilike

I have a simple Tag class with only two fields, name and value,
class Tag {
String name
String value
}
and I'm trying to render an XML where I want to search for parts of both parameters via findBy...Ilike().
def getXml = {
render Tag.findAllByNameAndValueIlike("%${params.name}%", "%${params.value}%") as XML
}
But this doesn't give my any results. If I use only one parameter, it works as I expect:
def getXml = {
render Tag.findAllByNameIlike("%${params.name}%") as XML
}
My next question is probably going to be about filtering the results, and adding other "similar" tags to the returns list, so is there a way to solve the above with something like:
def getXml = {
list = Tag.findAllByNameIlike("%${params.name}%")
list.add(Some other stuff)
list.sortBy(Some thing, maby name length)
}
For your multiple-field ilike query you can use withCriteria:
def result = Tag.withCriteria {
ilike('name', "%${params.name}%")
ilike('value', "%${params.value}%")
}
This will return a list of Tag domains whose name matches the provided name and value matches the provided value.
The Criteria DSL will probably let you do most of the filtering you need, but you can also consider using some of the Groovy collection examples here.
You have to put the restrictions(InList, NotNull, etc) on each field of a dynamic finder. If you do not, it assumes equals. Here is what you were looking for:
Tag.findAllByNameIlikeAndValueIlike("%${params.name}%", "%${params.value}%")
Both answer are good. I tried both, but I have to say I like the withcCritia the best. It seems very flexibly.
def result = Tag.withCriteria {
if(params.name != null)
ilike('name', "%${params.name}%")
if(params.value != null)
ilike('value', "%${params.value}%")
}
result.add(new Tag('name': "something"))
render result as XML

How would I find the text of a node that has a specific value for an attribute in groovy?

I'm using XMLSlurper. My code is below (but does not work). The problem is that it fails when it hits a node that does not have the attribute "id". How do I account for this?
//Parse XML
def page = new XmlSlurper(false,false).parseText(xml)
//Now save the value of the proper node to a property (this fails)
properties[ "finalValue" ] = page.find {
it.attributes().find { it.key.equalsIgnoreCase( 'id' ) }.value == "myNode"
};
I just need to account for nodes without "id" attribute so it doesn't fail. How do I do that?
You could alternatively use the GPath notation, and check if "#id" is empty first.
The following code snippet finds the last element (since the id attribute is "B" and the value is also "bizz", it prints out "bizz" and "B").
def xml = new XmlSlurper().parseText("<foo><bar>bizz</bar><bar id='A'>bazz</bar><bar id='B'>bizz</bar></foo>")
def x = xml.children().find{!it.#id.isEmpty() && it.text()=="bizz"}
println x
println x.#id
Apprently I can get it to work when I simply use depthFirst. So:
properties[ "finalValue" ] = page.depthFirst().find {
it.attributes().find { it.key.equalsIgnoreCase( 'id' ) }.value == "myNode"
};

list.find(closure) and executing against that value

Really my question is "Can the code sample below be even smaller? Basically the code sample is designed to first look through a list of objects, find the most granular (in this case it is branch) and then query backwards depending on what object it finds.
1 - If it finds a branch, return the findAllBy against the branch
2 - If it finds a department, return the findAllBy against the department
3 - If it finds an organization, return the findAllBy against the organization
The goal is to find the most granular object (which is why order is important), but do I need to have two separate blocks (one to define the objects, the other to check if they exist)? Or can those two executions be made into one command...
def resp
def srt = [sort:"name", order:"asc"]
def branch = listObjects.find{it instanceof Branch}
def department = listObjects.find{it instanceof Department}
def organization = listObjects.find{it instanceof Organization}
resp = !resp && branch ? Employees.findAllByBranch(branch,srt) : resp
resp = !resp && department ? Employees.findAllByDepartment(department,srt) : resp
resp = !resp && organization ? Employees.findAllByOrganization(organization,srt) : resp
return resp
What I'm thinking is something along the lines of this:
def resp
resp = Employees.findAllByBranch(listObjects.find{it instanceof Branch})
resp = !resp ? Employees.findAllByDepartment(listObjects.find{it instanceof Department}) : resp
resp = !resp ? Employees.findAllByOrganization(listObjects.find{it instanceof Organization}) : resp
But I believe that will throw an exception since those objects might be null
You can shorten it up a bit more with findResult instead of a for in loop with a variable you need to def outside:
def listObjects // = some predetermined list that you've apparently created
def srt = [sort:"name", order:"asc"]
def result = [Branch, Department, Organization].findResult { clazz ->
listObjects?.find { it.class.isAssignableFrom(clazz) }?.with { foundObj ->
Employees."findAllBy${clazz.name}"(foundObj, srt)
}
}
findResult is similar to find, but it returns the result from the first non-null item rather than the item itself. It avoids the need for a separate collection variable outside of the loop.
Edit: what I had previously didn't quite match the behavior that I think you were looking for (I don't think the other answers do either, but I could be misunderstanding). You have to ensure that there's something found in the list before doing the findAllBy or else you could pull back null items which is not what you're looking for.
In real, production code, I'd actually do things a bit differently though. I'd leverage the JVM type system to only have to spin through the listObjects once and short circuit when it found the first Branch/Department/Organization like this:
def listObjects
def sort = [sort:"name", order:"asc"]
def result = listObjects?.findResult { findEmployeesFor(it, sort) }
... // then have these methods to actually exercise the type specific findEmployeesFor
def findEmployeesFor(Branch branch, sort) { Employees.findAllByBranch(branch, sort) }
def findEmployeesFor(Department department, sort { Employees.findAllByDepartment(department, sort)}
def findEmployeesFor(Organization organization, sort { Employees.findAllByOrganization(organization, sort)}
def findEmployeesFor(Object obj, sort) { return null } // if listObjects can hold non/branch/department/organization objects
I think that this code is actually clearer and it reduces the number of times we iterate over the list and the number of reflection calls we need to make.
Edit:
A for in loop is more efficient, since you want to break processing on first non-null result (i.e. in Groovy we cannot break out of a closure iteration with "return" or "break").
def resp
for(clazz in [Branch,Department,Organization]) {
resp = Employees."findAllBy${clazz.name}"(listObjects?.find{it instanceof $clazz})
if(resp) return
}
if(resp) // do something...
Original:
List results = [Branch,Department,Organization].collect{clazz->
Employees."findAllBy${clazz.name}"(listObjects?.find{it instanceof $clazz})
}
Enjoy Groovy ;--)
I think #virtualeyes nearly had it, but instead of a collect (which as he says you can't break out of), you want to use a find, as that stops running the first valid result it gets:
List results = [Branch,Department,Organization].find { clazz->
Employees."findAllBy${clazz.name}"(listObjects?.find{it instanceof clazz})
}

Groovy - Type testing?

I'm really brand new to Groovy and I'm trying to get something done. I've written some Groovy code (which works just fine) which receives some text. This text should be an integer (between 0 and 10). It may just happen a user enters something different. In that case I want to do some specific error handling.
Now I'm wondering, what's the best / grooviest way to test if a string-typed variable can be casted to an integer?
(what I want to do is either consume the integer in the string or set the outcome of my calculation to 0.
Thanks!
The String class has a isInteger() method you could use:
def toInteger (String input) {
if (input?.isInteger()) {
return input.toInteger()
}
return 0
}
use groovy contains
if ( x?.isInteger()) {
return (0..10).contains(x)
} else {
return false
}
Is this what you're saying?
Integer integer = 0
try {
integer = (Integer) string
assert integer > 0
assert integer < 10
catch(e) {
integer = 0
}
There are lots of ways this can be done in groovy, if you're comfortable with regular expressions, this is about as concise as you can get:
def processText(String text) {
text ==~ /(10|\d)/ ? text.toInteger() : 0
}
assert 0 == processText("-1")
(0..10).each {
assert it == processText("$it")
}
assert 0 == processText("11")
I'm a little unsure what you mean by "specific error handling" if the user does something different.
If this is a web application, I'd take a look at grails and the constraints that you can put on the fields of a domain object, that would let you easily express what you're trying to do.
You have the grails tag on your question, so if you are using Grails, you might consider making this an Integer property on a domain class. The param may come in as text, but you can bind it to an integer property with a default value of 0:
class MyDomain {
Integer whatever = 0
static constraints = {
whatever( min:0, max:10)
}
}

Resources