I'm attempting to do a unit test for a Queueable that does an Http callout. When I run the test I get an exception: "System.CalloutException: Callout loop not allowed". Previously I was using @future rather than Queueable and the test ran fine.
Anyone have an idea of what's happening here?
OutboundMessageSender
public class OutboundMessageSender implements Queueable, Database.AllowsCallouts {
private Rest_Callout__c restCallout ;
private String endPoint ;
public void OutboundMessageSender( Rest_Callout__c rest_Callout )
{
restCallout = rest_Callout ;
}
public Rest_Callout__c getRestCallout() {
return restCallout;
}
public void setRestCallout( Rest_Callout__c rest_Callout ) {
restCallout = rest_Callout;
}
public String getEndPoint() {
return endPoint ;
}
public void setEndPoint( String endPointIn ) {
endPoint = endPointIn ;
}
public void execute( QueueableContext context ) {
String restCalloutBody = restCallout.Body__c ;
String restCalloutId = restCallout.ID ;
HTTPResponse response = sendHttpRequest( restCalloutBody ) ;
// Update the restCallout.
Rest_Callout__c restCallout = [Select ID, Response__c, Send_Counter__c,
SendDateTime__c From Rest_Callout__c Where ID = :restCalloutId] ;
restCallout.Send_Counter__c++ ;
restCallout.SendDateTime__c = Datetime.now() ;
if ( response == null )
{
restCallout.Response__c = null ;
}
else
{
restCallout.Response__c = response.getBody() ;
}
update restCallout ;
}
public HTTPResponse sendHttpRequest( String restCalloutBody )
{
HTTPResponse response = null ;
String hsdpUrl = '' ;
try
{
// Construct the HTTPRequest.
HTTPRequest request = new HTTPRequest() ;
request.setEndpoint( 'callout:' + endPoint ) ;
request.setMethod( 'POST' ) ;
request.setHeader( 'Accept', 'application/json' ) ;
request.setHeader( 'Content-Type', 'application/json' ) ;
request.setBody( JSON.serialize( restCalloutBody ) ) ;
// Send the request.
HTTP http = new HTTP() ;
response = http.Send( request ) ;
}
catch ( Exception e )
{
System.debug( 'Error sending observation to HSDP due to: ' + e ) ;
}
return response ;
}
}
OutboundMessageSenderMockService
@isTest
global class OutboundMessageSenderMockService implements HttpCalloutMock
{
global HTTPResponse respond( HTTPRequest request )
{
System.assertEquals( request.getEndpoint(),
'https://hsdp.server.com/patient' ) ;
System.assertEquals( request.getMethod(), 'POST' ) ;
HTTPResponse response = new HTTPResponse() ;
response.setHeader( 'Content-Type', 'application/json' ) ;
response.setBody( '{ "Message" : "Success" }' ) ;
response.setStatusCode( 200 ) ;
return response ;
}
}
OutboundMessageSenderTest
@isTest
public Class OutboundMessageSenderTest
{
@isTest
static void testOutboundMessageSenderExecute()
{
Rest_Callout__c restCallout = insertRestCallout() ;
ecc_generateTestData.generateConfiguration( false ) ;
OutboundMessageSender messageSender = new OutboundMessageSender() ;
messageSender.setRestCallout( restCallout );
messageSender.setEndPoint( 'IBE_Observation_Test' ) ;
Test.setMock( HttpCalloutMock.class, new
OutboundMessageSenderMockService() ) ;
Test.startTest() ;
ID jobID = System.enqueueJob( messageSender ) ;
Test.stopTest() ;
Rest_Callout__c postExecuteRestCallout =
[Select Response__c From Rest_Callout__c Where ID = :restCallout.ID] ;
String responseBody = postExecuteRestCallout.Response__c ;
System.assertEquals( '{ "Message" : "Success" }', responseBody ) ;
}
static private Rest_Callout__c insertRestCallout()
{
// Construct the RestCallout instance for this test.
Rest_Callout__c restCallout = new Rest_Callout__c() ;
restCallout.Body__c = 'something to send somewhere over the rainbow' ;
restCallout.Send_Counter__c = 0 ;
restCallout.SendDateTime__c = Datetime.now() ;
insert restCallout;
return restCallout ;
}
}
Best Answer
I believe you're looking at a Platform bug - as far as I can tell, setMock is not working for callouts in Queueable Apex classes at this time. I've filed a case and am waiting to hear back.
Update 8/1/2015 - This has been confirmed as a platform bug.