function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Padmini S 26Padmini S 26 

System.StringException: Unrecognized base64 character: in Test Class

Hi All,

I am getting the System.StringException: Unrecognized base64 character: in Test Class.

I have written the below Apex Code to update the Course Registration Details.
 global static String updateCourseRegistration(){
   RestRequest req = RestContext.request;
        RestResponse res = Restcontext.response;
        String Endpoint=req.requestURI;
        
        string enrCourseComDate=endpoint.substring(endpoint.lastIndexOf('/')+1);
        String enrCourseComDateUTF= EncodingUtil.urlDecode(enrCourseComDate,'UTF-8');
        enrCourseComDateUTF= EncodingUtil.urlDecode(enrCourseComDateUTF,'UTF-8');
        Blob decodedB64 = EncodingUtil.base64Decode(enrCourseComDateUTF);
        Blob decryptedBlob = Crypto.decrypt('AES256', blob.valueof(cryptoKey),blob.valueof(IV), decodedB64);
        string CourseComDate=decryptedBlob.toString();
         if(courseComDate.length()==8){
            endpoint=endpoint.removeEnd('/'+enrCourseComDate);
            String encEnCourseId= endpoint.substring(endpoint.lastIndexOf('/')+1);
            encEnCourseId= EncodingUtil.urlDecode(encEnCourseId,'UTF-8');
            encEnCourseId= EncodingUtil.urlDecode(encEnCourseId,'UTF-8');
            Blob decodedB641 = EncodingUtil.base64Decode(encEnCourseId);
            Blob decryptedBlob1 = Crypto.decrypt('AES256', blob.valueof(cryptoKey),blob.valueof(IV), decodedB641);
            string enCourseId=decryptedBlob1.toString();
            if(enCourseId.length()==5){
                List<Course_Registration__c> cr=[select id,name,Course_Instance_LMS_Mode__c,LMS1_Enrcourse_ID__c,Registration_Date__c,Course_completion_Date__c from Course_Registration__c where
                                                    LMS1_Enrcourse_ID__c=:enCourseId];
                if(cr.size()>0){                                    
                    if(cr[0].Course_Instance_LMS_Mode__c!='Blended')
                        cr[0].LMS_Status__c='Completed';
                    else
                        cr[0].LMS_Status__c='Blended course completed';
                    update cr;
                  return '2000-Successful';
                }

Test Class:

@isTest
private class TestUpdateCourseCompletionStatusService 
{
    public static testmethod void testupdate() {
     LMSCredentials__c lmsc = new LMSCredentials__c ();
    lmsc.Prod_CryptoKey__c = 'prod crypto';
    lmsc.Test_CryptoKey__c = 'test crypto';
    lmsc.Prod_IV__c = 'prod iv';
    lmsc.Test_IV__c = 'test iv';
    insert lmsc;
    Course_Registration__c coursereg = new Course_Registration__c();
    coursereg.Name__c = 'testcourse';
    coursereg.ID_Number__c = '1234';
    coursereg.LMS_Status__c ='Completed';
    insert coursereg;
   System.RestContext.request = new RestRequest();
     RestContext.request.requestURI = '/UpdateCourseCompletionStatus/*';
     RestContext.request.addHeader('decodedB641 ', '12345');
     UpdateCourseCompletionStatusService.updateCourseRegistration();
}
}

I am getting the error as "System.StringException: Unrecognized base64 character: " and stack trace as Class.System.EncodingUtil.base64Decode: line 5, column 1
Class.UpdateCourseCompletionStatusService.updateCourseRegistration: line 28, column 1
Class.TestUpdateCourseCompletionStatusService.testupdate: line 30, column 1.

Thanks in Advance.
Manish BhatiManish Bhati
You can't directly decode a plain string. Any String should be encoded first to decode, so in your case it is getting unrecognized character on line 28 of your  UpdateCourseCompletionStatusService class.
Try to put some system.debug(); to see which values are going to line No. 28 (I can't know exactly from your code here that which is line no.28, always try to put code using add a code sample from the toolbar while writing any post).
Padmini S 26Padmini S 26
Hi Manish,

Thanks for your helping. Below is the apex class which i have implemented.
 
@RestResource(urlMapping='/UpdateCourseCompletion/*')
global with sharing class CourseCompletion
{
 @HttpPost
    global static String updateCourseRegistration(){
    String cryptoKey;
    String IV;
    LMS__c lms=new LMS__c();
        lms = LMS__c.getinstance();   // Custom Setting
        if(UserInfo.getOrganizationId() == 'ProductionID') { // prod instance
            cryptoKey=lms.Prod_CryptoKey__c;
            IV=lms.Prod_IV__c;    
        } 
        else {   //sandbox
            cryptoKey=lms.Test_CryptoKey__c;
            IV=lms.Test_IV__c; 
        } 
        RestRequest req = RestContext.request;
        RestResponse res = Restcontext.response;
        String Endpoint=req.requestURI;
        string enrCourseComDate=endpoint.substring(endpoint.lastIndexOf('/')+1);
        String enrCourseComDateUTF= EncodingUtil.urlDecode(enrCourseComDate,'UTF-8');
        enrCourseComDateUTF= EncodingUtil.urlDecode(enrCourseComDateUTF,'UTF-8');
        Blob decodedB64 = EncodingUtil.base64Decode(enrCourseComDateUTF);
        Blob decryptedBlob = Crypto.decrypt('AES256', blob.valueof(cryptoKey),blob.valueof(IV), decodedB64);
        string CourseComDate=decryptedBlob.toString();
         if(courseComDate.length()==8){
            endpoint=endpoint.removeEnd('/'+enrCourseComDate);
            String encEnCourseId= endpoint.substring(endpoint.lastIndexOf('/')+1);
            encEnCourseId= EncodingUtil.urlDecode(encEnCourseId,'UTF-8');
            encEnCourseId= EncodingUtil.urlDecode(encEnCourseId,'UTF-8');
            Blob decodedB641 = EncodingUtil.base64Decode(encEnCourseId);
            Blob decryptedBlob1 = Crypto.decrypt('AES256', blob.valueof(cryptoKey),blob.valueof(IV), decodedB641);
            string enCourseId=decryptedBlob1.toString();
            if(enCourseId.length()==5){
                List<Registration__c> cr=[select id,name,Course_Instance_LMS_Mode__c,LMS1_Enrcourse_ID__c,Registration_Date__c,Course_completion_Date__c from Registration__c where
                                                    LMS1_Enrcourse_ID__c=:enCourseId];
                if(cr.size()>0){                                    
                    Integer dateint=integer.valueof(courseComDate.substring(0,2));
                    Integer monthint=integer.valueof(courseComDate.substring(2,4));
                    Integer yint=integer.valueof(courseComDate.substring(4,8));
                    Date d = Date.newInstance(yint, monthint, dateint);
                    if(cr[0].Course_Instance_LMS_Mode__c!='Blended')
                        cr[0].Course_completion_Date__c=d;
                    //cr[0].LMS_Platform__c='WizLearn';
                    if(cr[0].Course_Instance_LMS_Mode__c!='Blended')
                        cr[0].LMS_Status__c='Completed';
                    else
                        cr[0].LMS_Status__c='Blended course completed';
                    update cr;
                  return '2000-Successful';
                }
                else
                    return '1003-EnrCourseId not found in SFDC';
            }
            else
                return '1002-Invalid EnrCourseID';
        }
        else 
            return '1001-Invalid Date';
   }
}

I wrote test class as below.
 
@isTest
private class TestUpdateCourseCompletionStatusService 
{
    public static testmethod void testupdate() {
     LMS__c lmsc = new LMS__c ();
    lmsc.Prod_CryptoKey__c = 'prod crypto';
    lmsc.Test_CryptoKey__c = 'test crypto';
    lmsc.Prod_IV__c = 'prod iv';
    lmsc.Test_IV__c = 'test iv';
    insert lmsc;
    Registration__c coursereg = new Registration__c();
    coursereg.Name__c = 'testcourse';
    coursereg.ID_Number__c = '1234';
    coursereg.LMS_Status__c ='Completed';
    insert coursereg;
   System.RestContext.request = new RestRequest();
     RestContext.request.requestURI = '/UpdateCourseCompletion/*';
     RestContext.request.addHeader('decodedB641 ', '12345');
    CourseCompletion.updateCourseRegistration();
  }
}

I am getting the error as System.StringException: Unrecognized base64 character: *
Stack TraceClass.System.EncodingUtil.base64Decode: line 5, column 1
Class.UpdateCourseCompletionStatusService.updateCourseRegistration: line 28, column 1
Class.TestUpdateCourseCompletionStatusService.testupdate: line 30, column 1.

Thanks in Advance. Kindly help me how to write the test class for this apex class.

 
Manish BhatiManish Bhati
Can you tell the corresponding line in the above code I see in test and apex class:-

Class.UpdateCourseCompletionStatusService.updateCourseRegistration: line 28, column 1
Class.TestUpdateCourseCompletionStatusService.testupdate: line 30, column 1

i.e.line 28 in your class to the one I see above in the added code sample, also line 30 in test to the added code.
Padmini S 26Padmini S 26
line 28 in apex class is :
Blob decodedB64 = EncodingUtil.base64Decode(enrCourseComDateUTF);

line 30 in test class is:
UpdateCourseCompletionStatusService.updateCourseRegistration();
Manish BhatiManish Bhati
Just put
system.debug(enrCourseComDateUTF);
before line 28 and see the debug logs.

Tell me the output. 
Padmini S 26Padmini S 26
enrCourseComDateUTF value comes from different system.
Manish BhatiManish Bhati
That is ok but what is coming when you are testing, because it seems like the value is having characters like * or /
Padmini S 26Padmini S 26
enrCourseComDateUTF value is having % character .Below is the value.
UTuMLMQ%253d%253d/xQuWVTp%252fpYYYLCDYgBJZvA%253d%253d

 
Manish BhatiManish Bhati
You are passing a UrlDecoded String value to 
Blob decodedB64 = EncodingUtil.base64Decode(enrCourseComDateUTF);

which is having % inbetween.
All I can figure out is that at the end you want a Blob value from enrCourseComDate so that it can be used in decryptedBlob in line no.25( in added code apex).

You have to maintain a sequence for encoding and decoding as perfectly explained in the below article:-
http://eltoro.force.com/BlobsStringsEncoding 

I could change your code and write, but I can't figure out if I misses any imp thing. Also I have to dig little deeper.
Hope you can carry from here as the article will be really helpful.
Padmini S 26Padmini S 26
Hi Manish,

Could you please give me some sample apex code which one explain the Blob and also give me the sample test class.

Thanks in Advance.
Manish BhatiManish Bhati
If I assume the URL is already encoded then:-
@RestResource(urlMapping='/UpdateCourseCompletion/*')
global with sharing class CourseCompletion
{
 @HttpPost
    global static String updateCourseRegistration(){
    String cryptoKey;
    String IV;
    LMS__c lms=new LMS__c();
        lms = LMS__c.getinstance();   // Custom Setting
        if(UserInfo.getOrganizationId() == 'ProductionID') { // prod instance
            cryptoKey=lms.Prod_CryptoKey__c;
            IV=lms.Prod_IV__c;    
        } 
        else {   //sandbox
            cryptoKey=lms.Test_CryptoKey__c;
            IV=lms.Test_IV__c; 
        } 
        RestRequest req = RestContext.request;
        RestResponse res = Restcontext.response;
        String Endpoint=req.requestURI;
        string enrCourseComDate=endpoint.substring(endpoint.lastIndexOf('/')+1);
        //Added by Manish (enrCourseComDate should be UrlEncoded UTF String)
        Blob b = Blob.valueOf(enrCourseComDate);
        String enrCourseComDateUTF= EncodingUtil.base64Encode(b);
        Blob decodedB64 = EncodingUtil.base64Decode(enrCourseComDateUTF);
        Blob decryptedBlob = Crypto.decrypt('AES256', blob.valueof(cryptoKey),blob.valueof(IV), decodedB64);
        string CourseComDate=decryptedBlob.toString();
         if(courseComDate.length()==8){
            endpoint=endpoint.removeEnd('/'+enrCourseComDate);
            String encEnCourseId= endpoint.substring(endpoint.lastIndexOf('/')+1);
            encEnCourseId= EncodingUtil.urlDecode(encEnCourseId,'UTF-8');
            encEnCourseId= EncodingUtil.urlDecode(encEnCourseId,'UTF-8');
            Blob decodedB641 = EncodingUtil.base64Decode(encEnCourseId);
            Blob decryptedBlob1 = Crypto.decrypt('AES256', blob.valueof(cryptoKey),blob.valueof(IV), decodedB641);
            string enCourseId=decryptedBlob1.toString();
            if(enCourseId.length()==5){
                List<Registration__c> cr=[select id,name,Course_Instance_LMS_Mode__c,LMS1_Enrcourse_ID__c,Registration_Date__c,Course_completion_Date__c from Registration__c where
                                                    LMS1_Enrcourse_ID__c=:enCourseId];
                if(cr.size()>0){                                    
                    Integer dateint=integer.valueof(courseComDate.substring(0,2));
                    Integer monthint=integer.valueof(courseComDate.substring(2,4));
                    Integer yint=integer.valueof(courseComDate.substring(4,8));
                    Date d = Date.newInstance(yint, monthint, dateint);
                    if(cr[0].Course_Instance_LMS_Mode__c!='Blended')
                        cr[0].Course_completion_Date__c=d;
                    //cr[0].LMS_Platform__c='WizLearn';
                    if(cr[0].Course_Instance_LMS_Mode__c!='Blended')
                        cr[0].LMS_Status__c='Completed';
                    else
                        cr[0].LMS_Status__c='Blended course completed';
                    update cr;
                  return '2000-Successful';
                }
                else
                    return '1003-EnrCourseId not found in SFDC';
            }
            else
                return '1002-Invalid EnrCourseID';
        }
        else 
            return '1001-Invalid Date';
   }
}

Try this, it should not throw any error if:-
-URL is already encoded.
Padmini S 26Padmini S 26
Hi Manish,

Thank you for helping. But the requirement that, we are decoding twice because third party tool is encoding the two times. Could you please provide me the sample test class for this.

Thanks in Advance.
Manish BhatiManish Bhati
Ok. So, you mean it is UrlEncoded twice but, what about base64Encode?
Whether it is base64Encoded or not?

See we have three things here:-
UrlEncoding - Encodes a string into the application/x-www-form-urlencoded format using a specific encoding scheme, for example “UTF-8.”
base64Encode - Converts a Blob to an unencoded String representing its normal form and 
encrypt - Which encrypts some data to return Cipher text.

So, first you should be clear what third party tool doing and in which order.
Accordingly you should do the reverse process of UrlDecode, base64Decode and decrypt.
Bhakti Gujarathi 6Bhakti Gujarathi 6
Hey, 
I am facing same problem. Can you help me with the solution? My controller is working perfectly for encoding and decoding the url, but test class is failing.
Padmini S 26Padmini S 26
Hi Bhakti,
My test class is pass. But i got code coverage is 23% only. Even i am also facing same problem. Can anybody help us would be appreciate.