I think this will be a easy fix, I am sure it is something I am just overlooking at the end of the day.
I created a mock class to test my callouts. It is called SingleRequestMockClass.cls, I got the structure from here: https://developer.salesforce.com/blogs/developer-relations/2013/03/testing-apex-callouts-using-httpcalloutmock.html .
When I pass it a 401
it for some reason doesn't register it. Shouldn't it just return the status code that I am setting it to? Can anyone see what I am doing wrong here?
public static String handleResponse(HttpResponse res){
system.debug('got into handle response:: ' + res);
String errorData = '';
String errorString;
Boolean resErrors;
if (res.getStatusCode() == 200) {
Error error = new Error();
resErrors = false;
System.JSONParser parser = JSON.createParser(res.getBody());
while (parser.nextToken() != null) {
if (parser.getCurrentToken() == JSONToken.START_OBJECT && parser.getCurrentName() == 'kind') {
resErrors = false;//all requests succeeded
}
if (parser.getCurrentToken() == JSONToken.START_OBJECT && parser.getCurrentName() == 'error') { //errors
resErrors = true;
error = (Error)parser.readValueAs(DoubleClick_Webservice.Error.class);
}
}
if(resErrors) { //error handling
errorString += '\n\nNew Error --- \nReason: ' + errorData;
}
else { //success handling
errorString = 'success';
}
}
else { //HTTP Error
//sending email to notify for authentication errors
if (res.getStatusCode() == 401) {
sendAuthErrorEmail(res);
}
errorString = 'StatusCode: ' +res.getStatusCode() + ' :: ' + res.getStatus();
Error error = new Error();
System.JSONParser parser = JSON.createParser(res.getBody());
while (parser.nextToken() != null) { //errors
if (parser.getCurrentToken() == JSONToken.START_OBJECT && parser.getCurrentName() == 'error') {
error = (Error)parser.readValueAs(DCS_SingleGoogleAppAuth_Webservice.Error.class);
}
}
List<Errors> errorsList = error.errors;
for (Errors e : errorsList) {
errorString += '\n\nNew Error --- \nReason: ' + e.reason + '\nMessage: ' + e.message;
}
}
return errorString;
}
TEST CLASS
static testmethod void testParseErrorCallout() {
Test.startTest();
SingleRequestMockClass fakeResponse = new SingleRequestMockClass(401, 'Complete', '{"access_token" : "ya22.123Ceuppb7J9123454654879878655dJTZlw","expires_in" : 3600,"token_type" : "Bearer"}', null);
Test.setMock(HttpCalloutMock.class, fakeResponse);
DoubleClickRefreshToken__c dcrt = new DoubleClickRefreshToken__c(Refresh_Token__c = '123', Key__c = '321', Secret__c = '456');
insert dcrt;
Lead l = new Lead(lastname='TestLead', Company = 'TestCompany', GCLID_ID__C = '123456', GCLSRC_ID__C = '32154');
insert l;
DoubleClick_Request__c dcr = new DoubleClick_Request__c(Related_Lead__c = l.id, Request_Failed__c = FALSE, Conversion_Status__c = 'New', Segmentation_Name__c = 'Test 1', Testmode__c = FALSE);
insert dcr;
Test.stopTest();
}
Callout:
public static HttpResponse retrieveAccessToken(DoubleClickRefreshToken__c doubleClickRefreshToken) {
HttpRequest req = new HttpRequest();
req.setMethod('POST');
req.setEndpoint('https://accounts.google.com/o/oauth2/token');
req.setHeader('content-type', 'application/x-www-form-urlencoded');
String messagebody = 'client_id=' + doubleClickRefreshToken.Key__c + '&client_secret=' + doubleClickRefreshToken.Secret__c + '&grant_type=refresh_token&refresh_token=' + doubleClickRefreshToken.Refresh_Token__c;
system.debug('this is the body ----------------->' + messagebody);
req.setHeader('Content-Length', String.valueOf(messagebody.length()));
req.setBody(messagebody);
req.setTimeout(120000);
Http h = new Http();
HttpResponse res;
try {
res = h.send(req);
system.debug('res in accesstoken2:: ' + res);
}
catch(Exception e){
system.debug('exception e:: ' + e);
}
return res;
}
It is getting caught on this line: if (parser.getCurrentToken() == JSONToken.START_OBJECT && parser.getCurrentName() == 'error')
but to my understanding, if the authorization token is incorrect (which is it), the there should be a string generated with the error code in it. Do I have to pass back this error code? Like this:
SingleRequestMockClass fakeResponse = new SingleRequestMockClass(401, 'Complete', '{"error": {"errors": [{"domain": "global","reason": "authError","message": "Invalid Credentials","locationType": "header","location": "Authorization"}],"code": 401,"message": "Invalid Credentials"}}', null);
Mock Class:
@isTest
public class SingleRequestMockClass implements HttpCalloutMock {
protected Integer code;
protected String status;
protected String bodyAsString;
protected Blob bodyAsBlob;
protected Map<String, String> responseHeaders;
public SingleRequestMockClass(Integer code, String status, String body, Map<String, String> responseHeaders) {
this.code = code;
this.status = status;
this.bodyAsString = body;
this.bodyAsBlob = null;
this.responseHeaders = responseHeaders;
}
public SingleRequestMockClass(Integer code, String status, Blob body, Map<String, String> responseHeaders) {
this.code = code;
this.status = status;
this.bodyAsBlob = body;
this.bodyAsString = null;
this.responseHeaders = responseHeaders;
}
public HTTPResponse respond(HTTPRequest req) {
HttpResponse resp = new HttpResponse();
resp.setStatusCode(code);
resp.setStatus(status);
if (bodyAsBlob != null) {
resp.setBodyAsBlob(bodyAsBlob);
} else {
resp.setBody(bodyAsString);
}
if (responseHeaders != null) {
for (String key : responseHeaders.keySet()) {
resp.setHeader(key, responseHeaders.get(key));
}
}
return resp;
}
}
SingleRequestMockClass
and edit out using edit the OP parts that are irrelevant to your issueelse
block (not 200 code), you continue on after checkingif (res.getStatusCode() == 401) { sendAuthErrorEmail(res); }
. Seems like maybe that edge case should be anelse if
rather than nested within theelse
.