@ApiOperation(value = "Update a user’s info", tags = { "Users" }, nickname = "updateUserInfo")
    @ApiResponses(value = {
            @ApiResponse(code = 200, message = "Indicates the user was found and the info has been updated."),
            @ApiResponse(code = 400, message = "Indicates the value was missing from the request body."),
            @ApiResponse(code = 404, message = "Indicates the requested user was not found or the user does not have info for the given key. Status description contains additional information about the error.")
    })
    @PutMapping(value = "/identity/users/{userId}/info/{key}", produces = "application/json")
    public UserInfoResponse setUserInfo(@ApiParam(name = "userId") @PathVariable("userId") String userId, @ApiParam(name = "key") @PathVariable("key") String key, @RequestBody UserInfoRequest userRequest) {

        User user = getUserFromRequest(userId);
        String validKey = getValidKeyFromRequest(user, key);

        if (userRequest.getValue() == null) {
            throw new FlowableIllegalArgumentException("The value cannot be null.");
        }

        if (userRequest.getKey() == null || validKey.equals(userRequest.getKey())) {
            identityService.setUserInfo(user.getId(), key, userRequest.getValue());
        } else {
            throw new FlowableIllegalArgumentException("Key provided in request body does not match the key in the resource URL.");
        }

        return restResponseFactory.createUserInfoResponse(key, userRequest.getValue(), user.getId());
    }
@Test
    public void testCreateUserInfoExceptions() throws Exception {
        User savedUser = null;
        try {
            User newUser = identityService.newUser("testuser");
            newUser.setFirstName("Fred");
            newUser.setLastName("McDonald");
            newUser.setEmail("no-reply@flowable.org");
            identityService.saveUser(newUser);
            savedUser = newUser;

            // Test creating without value
            ObjectNode requestNode = objectMapper.createObjectNode();
            requestNode.put("key", "key1");

            HttpPost httpPost = new HttpPost(SERVER_URL_PREFIX + RestUrls.createRelativeResourceUrl(RestUrls.URL_USER_INFO_COLLECTION, "testuser"));
            httpPost.setEntity(new StringEntity(requestNode.toString()));
            closeResponse(executeRequest(httpPost, HttpStatus.SC_BAD_REQUEST));

            // Test creating without key
            requestNode = objectMapper.createObjectNode();
            requestNode.put("value", "The value");

            httpPost.setEntity(new StringEntity(requestNode.toString()));
            closeResponse(executeRequest(httpPost, HttpStatus.SC_BAD_REQUEST));

            // Test creating an already existing info
            identityService.setUserInfo(newUser.getId(), "key1", "The value");
            requestNode = objectMapper.createObjectNode();
            requestNode.put("key", "key1");
            requestNode.put("value", "The value");

            httpPost.setEntity(new StringEntity(requestNode.toString()));
            closeResponse(executeRequest(httpPost, HttpStatus.SC_CONFLICT));

            // Test creating info for unexisting user
            httpPost = new HttpPost(SERVER_URL_PREFIX + RestUrls.createRelativeResourceUrl(RestUrls.URL_USER_INFO_COLLECTION, "unexistinguser"));
            httpPost.setEntity(new StringEntity(requestNode.toString()));
            closeResponse(executeRequest(httpPost, HttpStatus.SC_NOT_FOUND));

        } finally {

            // Delete user after test passes or fails
            if (savedUser != null) {
                identityService.deleteUser(savedUser.getId());
            }
        }
    }