Search code examples
unit-testinggrailsgrails-ormspock

Grails Spock writing unit / integration test case for SQL injections


To support future changes in REST API that that allows query the database using /query endpoint and uses JSON as data format for I/O starting to write down test cases.

My configs are:-

  1. Grails 2.3.8
  2. Spock testing framework

I'm concerned if we have some good support from Spock for writing test cases for SQL injections verification and up to what level generic it can be made.

When we say generic, it means that it should be hitting a different endpoint each time it is run. For example,

1st run : /api/users/query 
2nd run : /api/group/query
3rd run : /api/users/query
.
.
nth time : /api/specs/query

So, the domain chosen must be different each time. We can have some random number generated which can be used to identify Domain endpoint from a map or list of query endpoint urls for all domains.

But next thought comes to my mind is whether there could another test case in place that can call these test cases(that check for SQL injections for different endpoints on each run) a specified number of times to test it further and more accurately.


Solution

  • For hitting a different endpoint each time what you can do is create a list of URLMappings and can fetch a random controller each time from list.

    If you are not using custom urlmappings then you can iterate over all controller classes and can fetch their actions. But as you have a rest api, I'm assuming you have custom mappings defined in URLMappings.groovy file. In this case with the help of UrlMappingsArtefactHandler you can get the url mappings artifacts. Code for that would be:

    import org.codehaus.groovy.grails.commons.UrlMappingsArtefactHandler
    import org.codehaus.groovy.grails.web.mapping.DefaultUrlMappingEvaluator
    import org.codehaus.groovy.grails.web.mapping.UrlMapping
    import org.springframework.mock.web.MockServletContext
    
    private List<UrlMapping> getAllURLMappings(){
        ClassLoader classLoader = this.class.classLoader
        def mappings = grailsApplication.getArtefacts(UrlMappingsArtefactHandler.TYPE)
    
        MockServletContext mctx = classLoader.loadClass('org.springframework.mock.web.MockServletContext').newInstance()
        DefaultUrlMappingEvaluator evaluator = classLoader.loadClass("org.codehaus.groovy.grails.web.mapping.DefaultUrlMappingEvaluator").newInstance(mctx)
        List<UrlMapping> allMappings = []
    
        List<UrlMapping> grailsClassMappings
        for (mapping in mappings) {
            if (Script.isAssignableFrom(mapping.getClazz())) {
                grailsClassMappings = evaluator.evaluateMappings(mapping.getClazz())
            } else {
                grailsClassMappings = evaluator.evaluateMappings(mapping.getMappingsClosure())
            }
            allMappings.addAll(grailsClassMappings)
        }
        return allMappings
    }
    

    Then to fetch url patterns for a specific action from all mappings you can iterate over the result returned from above method using below method:

    private List<String> getMappingForAction(List<UrlMapping> mappings, String action){
        return mappings.findAll {
            UrlMapping mapping ->
                return mapping.actionName.equals(action)
        }*.urlData.urlPattern
    }
    

    And using java.util.Random class you can fetch a random endpoint each time:

    List<UrlMapping> allMappings = getAllURLMappings()
    List<String> mappings = getMappingForAction(allMappings, "query")
    
    int size = mappings.size()
    
    Random r = new Random()
    int index = r.nextInt(size - 0)
    
    println mappings[index]