Spock No thread-bound request found - grails

I have created a simple util class UtilService.groovy and when I tried to run write test case for it.
class UtilService {
static transactional = true
def messageSource
HttpServletRequest getCurrentRequest() {
GrailsWebRequest webUtils = WebUtils.retrieveGrailsWebRequest()
def request = webUtils.getCurrentRequest()
return request
}
String getMessage(String code, Object[] args = null, String defaultMessage = null) {
HttpServletRequest request = currentRequest
Locale locale = request.locale
if (defaultMessage) {
return messageSource.getMessage(code, args, defaultMessage, locale)
} else {
return messageSource.getMessage(code, args, locale)
}
}
Test case
#TestMixin(GrailsUnitTestMixin)
class UtilServiceSpec extends Specification {
void "Test get message"() {
setup:
def utilService = new UtilService()
when:
String data = utilService.getMessage("payCode.label")
then:
data == "Pay Code"
}
}
Error:
No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread?
I have searched and try some links from google but they did not work for me.

Obviously, you are doing it outside of web request, WebUtils.retrieveGrailsWebRequest() will fail because there's no web request going on. If your service is called from a controller during tests it should work.
Instead of you service depending on WebRequest, why don't you pass the Locale as an argument to getMessage, controllers can call getMessage and pass the request Locale, or else the service will choose the default locale. Its generally not good idea to have services be aware of web apis (eg requests, response, session etc). And you will be able to test both service and controller.

I have written Integration test for this requirement rather than Unit test and able to run my test cases successfully.

Related

OWIN Authentication and Custom Response

I create a custom BasicAuthenticationMiddleware that use a BasicAuthenticationHandler to Authenticate requests from client to WebAPI.
The BasicAuthenticationHandler derives from the AuthenticationHandler< TOptions > base class.
Everything works fine and I implemented the
AuthenticateCoreAsync
where the logic to authenticate happens
ApplyChallengeResponseAsync
where the logic, in case of not authenticated requests, sends the WWW-Authenticate header to the client.
What I would like to achieve now is to set a Custom Body in the Response (IOwinResponse, inside the ApplyChallengeResponseAsync, with a custom object like:
{
Code="999",
Description="My failing reason"
AdditionalInfo = "My additional infos"
}
instead of the standard message that is like
{
message="Authorization has been denied for this request."
}
Did you have any suggestion on this?
thanks
The standard message you see, which is "Authorization has been denied for this request." is created by the Authorize filter. The HandleUnauthorizedRequest method sets this message in the response.
protected virtual void HandleUnauthorizedRequest(HttpActionContext actionContext)
{
if (actionContext == null)
{
throw Error.ArgumentNull("actionContext");
}
actionContext.Response = actionContext.ControllerContext.Request
.CreateErrorResponse(
HttpStatusCode.Unauthorized,
SRResources.RequestNotAuthorized);
}
SRResources.RequestNotAuthorized is what you see as the standard message.
Now, ApplyChallengeResponseAsync is called from the OnSendingHeaders callback in Katana autentication micro framework. This callback is invoked when a component writes into the response stream. In our case, when the response message created by the filter (what you see above) gets serialized, that is when the callback is invoked and ApplyChallengeResponseAsync runs. By that time, it is already too late for you to change the response. The best bet will be to override the virtual method of the Authorize filter above like this.
public class MyAuthorizeAttribute : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)
{
var response = actionContext.Request.CreateResponse<MyError>
(new MyError() { Description = "My failing reason" });
response.StatusCode = HttpStatusCode.Unauthorized;
actionContext.Response = response;
}
}
public class MyError
{
public string Description { get; set; }
}
Instead of using [Authorize] on the controller or action method, use [MyAuthorize].

Putting an object on a Request in a Grails Integration Test

In a Grails project I am looking at here, a filter puts a Domain object on the request...
class TokenFilters {
def filters = {
all( uri: '/hiphop/**' ) {
before = {
MyToken myToken = ...
request.myToken = myToken
MyToken looks like:
class MyToken {
String id
String token
static mapping = {
token( index: true )
id( generator: 'uuid' )
}
...
}
In my controller, the myToken is pulled off the request.
MyController {
myaction {
MyToken accessToken = request.myToken
All fine. I wish to write an integration test for the controller.
#Test
void testLogin() {
def mc = new MyController()
def myToken = new MyToken(1234);
// set the request parameters
mc.request.parameters = [myToken:myToken];
def message = mc.action();
assertTrue(message.indexOf("trans") > 0)
}
When I run this, I get:
Failure: testLogin(MyTests)
| java.lang.IllegalArgumentException: Parameter map value must be single value or array of type [java.lang.String]
at testLogin(MyTests.groovy:40)
So it looks like Grails will only let me a String or a single value and doesn't like me putting an object on the request in the Filter. Even thou it lets me put on the same object type in a Filter.
I'd really like to test this without going to Functional tests. Please help. I am using Grails 2.2.1
Thanks
The problem is that your code is passing parameters to the controller. Your emulating an HTTP request which can't handle objects. What you can do is:
mc.request.parameters = [myToken: '1234']
and then you're controller/filter would pull out the 1234 and look up MyToken. If you were testing the controller forwarding then you can put objects in the request. Not the other way around.
I see now that part of the problem is that you're trying to test a controller that is assuming data coming from a filter.
You've omitted some code, but assuming you are extending ControllerUnitTestCase then you have access to a mock request object. You should be able to simply do:
#Test
void testLogin() {
def mc = new MyController()
def myToken = new MyToken(1234);
// set the request parameters
request.myToken = myToken
def message = mc.action();
assertTrue(message.indexOf("trans") > 0)
}

is it possible to set a global branded error page for 404's a using dropwizard

I find myself working a grails application that is being deployed as a fat jar built by a custom plugin that uses dropwizard to configure jetty.
It seems as though dropwizard doesn't allow facilitate the use of a plain old web.xml or jetty.xml and instead everything is set by java config at startup (i.e. using com.yammer.dropwizard.config.Environment).
Am I missing something here? Is there some way to map a 404 back to a URL or any kind of web page I can override so that a Jetty 404 isn't the default.
(yes I'm aware I could do something with the load balancer to redirect 404s)
I dont know how it is in grails, but this helps in java with dropwizard 0.7.1 run() method:
ResourceConfig jrConfig = environment.jersey().getResourceConfig();
environment.jersey().register(new RestErrorsHandler(jrConfig ));
Create this class for the mapping of exceptions -> give back an individual response!
#Provider
public class RestErrorsHandler implements ExceptionMapper<Exception> {
/**
* Deletes all ExpetionMappers.
*
* #param jrConfig
*/
public RestErrorsHandler(
ResourceConfig jrConfig)
{
// Remove all of Dropwizard's custom ExceptionMappers
Set<?> dwSingletons = jrConfig.getSingletons();
List<Object> singletonsToRemove = new ArrayList<Object>();
for (Object s : dwSingletons) {
// Remove all Exception mappers
if (s instanceof ExceptionMapper) {
singletonsToRemove.add(s);
}
}
for (Object s : singletonsToRemove) {
jrConfig.getSingletons().remove(s);
}
}
public Response toResponse(
Exception exception)
{
//Handle different exceptions in another way
if (exception.getClass().equals(JsonParseException.class)){
Response response = RestErrorsHandler.generalResponse(exception);
return response ;
} else if(exception.getClass().equals(JsonParseException.class)){
Response response = RestErrorsHandler.generalResponse(exception);
return response ;
} else if(exception.getClass().equals(Class.class)){
Response response = RestErrorsHandler.generalResponse(exception);
return response ;
}
//genral problem -> output default
Response response = RestErrorsHandler.generalResponse(exception);
return response ;
}
public static Response generalResponse(Exception exception)
{
return Response.status(Status.BAD_REQUEST).type(MediaType.TEXT_PLAIN)
.entity("if you just want to give back a string, but could also be default html page or whatever").build();
}
}

grailsApplication null in Service

I have a Service in my Grails application. However I need to reach the config for some configuration in my application. But when I am trying to use def grailsApplication in my Service it still gets null.
My service is under "Services".
class RelationService {
def grailsApplication
private String XML_DATE_FORMAT = "yyyy-MM-dd"
private String token = 'hej123'
private String tokenName
String WebserviceHost = 'xxx'
def getRequest(end_url) {
// Set token and tokenName and call communicationsUtil
setToken();
ComObject cu = new ComObject(tokenName)
// Set string and get the xml data
String url_string = "http://" + WebserviceHost + end_url
URL url = new URL(url_string)
def xml = cu.performGet(url, token)
return xml
}
private def setToken() {
tokenName = grailsApplication.config.authentication.header.name.toString()
try {
token = RequestUtil.getCookie(grailsApplication.config.authentication.cookie.token).toString()
}
catch (NoClassDefFoundError e) {
println "Could not set token, runs on default instead.. " + e.getMessage()
}
if(grailsApplication.config.webservice_host[GrailsUtil.environment].toString() != '[:]')
WebserviceHost = grailsApplication.config.webservice_host[GrailsUtil.environment].toString()
}
}
I have looked on Inject grails application configuration into service but it doesn't give me an answer as everything seems correct.
However I call my Service like this: def xml = new RelationService().getRequest(url)
EDIT:
Forgot to type my error, which is: Cannot get property 'config' on null object
Your service is correct but the way you are calling it is not:
def xml = new RelationService().getRequest(url)
Because you are instantiating a new object "manually "you are actually bypassing the injection made by Spring and so the "grailsApplication" object is null.
What you need to do is injecting your service using Spring like this:
class MyController{
def relationService
def home(){
def xml = relationService.getRequest(...)
}
}

Writing an Integration Test in Grails that will test DB persistence

My Integration-Test for my grails application is returning a null object when I try to get a domain object using grails dynamic get method.
This is a simplified example of my problem. Lets say I have a controller TrackerLogController that uses a service TrackerLogService to save an updated Log domain for another Tracker domain.
Domain Tracker:
class Tracker {
int id
String name
static hasMany = [logs: Log]
}
Domain Log:
class Log {
int id
String comment
static belongsTo = [tracker: Tracker]
}
Controller TrackerLogController save:
def TrackerLogService
def saveTrackerLog() {
def trackerId = params.trackerId
def trackerInstance = Tracker.get(trackerId)
Log log = TrackerLogService.saveTrackerLogs(trackerInstance, params.comment)
if( log.hasErrors() ){
//render error page
}
//render good page
}
Service TrackerLogService save:
Log saveTrackerLogs( Tracker tracker, String comment) {
Log log = new Log(tracker: tracker, comment: comment)
log.save()
return log
}
So now I want to write an Integration-Test for this service but I'm not sure if I should be writing one just for the simple logic in the controller (if error, error page else good page) I would think I would write a Unit test for that, and an Integration-Test to check the persistence in the Database.
This is what I have for my Integration-Test:
class TrackerLogServiceTests {
def trackerLogService
#Before
void setUp(){
def tracker = new Tracker(id: 123, name: "First")
tracker.save()
//Now even if I call Tracker.get(123) it will return a null value...
}
#Test
void testTrackerLogService() {
Tacker trackerInstance = Tracker.get(123) //I have tried findById as well
String commit = "This is a commit"
//call the service
Log log = trackerLogService.saveTrackerLogs(trackerInstance , commit)
//want to make sure I added the log to the tracker Instance
assertEquals log , trackerInstance.logs.findByCommit(commit)
}
}
So for this example my trackerInstance would be a null object. I know the Grails magic doesn't seem to work for Unit tests without Mocking, I thought for Intigration-Tests for persistence in the DB you would be able to use that grails magic.
You can't specify the id value unless you declare that it's "assigned". As it is now it's using an auto-increment, so your 123 value isn't used. It's actually ignored by the map constructor for security reasons, so you'd need to do this:
def tracker = new Tracker(name: "First")
tracker.id = 123
but then it would get overwritten by the auto-increment lookup. Use this approach instead:
class TrackerLogServiceTests {
def trackerLogService
private trackerId
#Before
void setUp(){
def tracker = new Tracker(name: "First")
tracker.save()
trackerId = tracker.id
}
#Test
void testTrackerLogService() {
Tacker trackerInstance = Tracker.get(trackerId)
String commit = "This is a commit"
//call the service
Log log = trackerLogService.saveTrackerLogs(trackerInstance , commit)
//want to make sure I added the log to the tracker Instance
assertEquals log , trackerInstance.logs.findByCommit(commit)
}
}
Also, unrelated - don't declare the id field unless it's a nonstandard type, e.g. a String. Grails adds that for you, along with the version field. All you need is
class Tracker {
String name
static hasMany = [logs: Log]
}
and
class Log {
String comment
static belongsTo = [tracker: Tracker]
}

Resources