Search code examples
springmd5mockmvc

How do I check whether a mockMvc response header is the MD5 representation of a part of my response?


I need to compare the MD5 hash of a specific value in my mockMvc response body to a header of the same request. I'm not sure how to do this given that there doesn't seem to be an easy way to get the content of a jsonPath or xPath matcher. I think something like this is the closest I've managed to get. I'm fairly sure I need to approach this from the header side since MD5 is not easily reversed.

mockMvc.perform(get(url)
                .session(session)
                .andExpect(header().string(ETAG,  convertToMD5(jsonPath("$.object.id"))));

Is there a way to do this, preferably without writing a custom Matcher?


Solution

  • After diving deep into the code used by Spring MockMvc, I found that eventually, the jsonPath().value(Object) ResultMatcher uses Object.equals() under the hood, and specifically the equals of the value parameter. Thus, I've found the easiest way to do this is to write an MD5Wrapper class that encapsulates a String object and define a custom equals method that compares the encapsulated String to an MD5 hash of the compared object.

    public class MD5Wrapper {
        private String mD5Hash;
    
        public MD5Wrapper(String md5Hash){
            mD5Hash = md5Hash;
        }
    
        public boolean equals(Object o2){
            if(o2 == null && mD5Hash == null){
                return true;
            }       
            if (o2 == null){
                return false;
            }
            if(mD5Hash == null){
                return false;
            }
            if(!(o2 instanceof String)){
                return false;
            }
            return org.apache.commons.codec.digest.DigestUtils.md5Hex((String)o2).equals(mD5Hash);
        }
    
        public String getmD5Hash() {
            return mD5Hash;
        }
    
        public String toString(){
            return mD5Hash;
        }
    
    }
    

    Then in the test itself, I retrieved the Etag header I needed, wrapped it and compared it to my ID:

    ResultActions resultActions = mockMvc.perform(get("/projects/1")
        .session(session)
        .contentType(contentTypeJSON)
        .accept(MediaType.APPLICATION_JSON))
        .... //various accepts
        ;
    
    MvcResult mvcResult = resultActions.andReturn();
    String eTAG = mvcResult.getResponse().getHeader(ETAG);
    resultActions.andExpect(jsonPath("$.id").value(new MD5Wrapper(eTAG.replace("\"", "")))); //our eTAG header is surrounded in double quotes, which have to be removed.
    

    So in the end, I didn't have to approach it from the header side as I originally thought, but rather from the jsonPath side.