@Override
    public synchronized RoleRecvStatus deliverRoleReply(RoleReplyInfo rri)
            throws SwitchStateException {
        long xid = rri.getXid();
        RoleState receivedRole = rri.getRole();
        RoleState expectedRole = pendingReplies.getIfPresent(xid);

        if (expectedRole == null) {
            RoleState currentRole = (sw != null) ? sw.getRole() : null;
            if (currentRole != null) {
                if (currentRole == rri.getRole()) {
                    // Don't disconnect if the role reply we received is
                    // for the same role we are already in.
                    // FIXME: but we do from the caller anyways.
                    log.debug("Received unexpected RoleReply from "
                            + "Switch: {}. "
                            + "Role in reply is same as current role of this "
                            + "controller for this sw. Ignoring ...",
                            sw.getStringId());
                    return RoleRecvStatus.OTHER_EXPECTATION;
                } else {
                    String msg = String.format("Switch: [%s], "
                            + "received unexpected RoleReply[%s]. "
                            + "No roles are pending, and this controller's "
                            + "current role:[%s] does not match reply. "
                            + "Disconnecting switch ... ",
                            sw.getStringId(),
                            rri, currentRole);
                    throw new SwitchStateException(msg);
                }
            }
            log.debug("Received unexpected RoleReply {} from "
                    + "Switch: {}. "
                    + "This controller has no current role for this sw. "
                    + "Ignoring ...",
                      rri,
                      sw == null ? "(null)" : sw.getStringId());
            return RoleRecvStatus.OTHER_EXPECTATION;
        }

        // XXX Should check generation id meaningfully and other cases of expectations
        //if (pendingXid != xid) {
        //    log.info("Received older role reply from " +
        //            "switch {} ({}). Ignoring. " +
        //            "Waiting for {}, xid={}",
        //            new Object[] {sw.getStringId(), rri,
        //            pendingRole, pendingXid });
        //    return RoleRecvStatus.OLD_REPLY;
        //}
        sw.returnRoleReply(expectedRole, receivedRole);

        if (expectedRole == receivedRole) {
            log.debug("Received role reply message from {} that matched "
                    + "expected role-reply {} with expectations {}",
                    sw.getStringId(), receivedRole, expectation);

            // Done with this RoleReply; Invalidate
            pendingReplies.invalidate(xid);
            if (expectation == RoleRecvStatus.MATCHED_CURRENT_ROLE ||
                    expectation == RoleRecvStatus.MATCHED_SET_ROLE) {
                return expectation;
            } else {
                return RoleRecvStatus.OTHER_EXPECTATION;
            }
        }

        pendingReplies.invalidate(xid);
        // if xids match but role's don't, perhaps its a query (OF1.3)
        if (expectation == RoleRecvStatus.REPLY_QUERY) {
            return expectation;
        }

        return RoleRecvStatus.OTHER_EXPECTATION;
    }
@Test
    public void deliverRoleReply() {
        RoleRecvStatus status;

        RoleReplyInfo asserted = new RoleReplyInfo(MASTER, GID, XID);
        RoleReplyInfo unasserted = new RoleReplyInfo(SLAVE, GID, XID);

        try {
            //call without sendRoleReq() for requestPending = false
            //first, sw.role == null
            status = manager.deliverRoleReply(asserted);
            assertEquals("expectation wrong", OTHER_EXPECTATION, status);

            sw.setRole(MASTER);
            assertEquals("expectation wrong", OTHER_EXPECTATION, status);
            sw.setRole(SLAVE);

            //match to pendingRole = MASTER, requestPending = true
            manager.sendRoleRequest(MASTER, MATCHED_CURRENT_ROLE);
            status = manager.deliverRoleReply(asserted);
            assertEquals("expectation wrong", MATCHED_CURRENT_ROLE, status);

            //requestPending never gets reset -- this might be a bug.
            status = manager.deliverRoleReply(unasserted);
            assertEquals("expectation wrong", OTHER_EXPECTATION, status);
            assertEquals("pending role mismatch", MASTER, ((TestSwitchDriver) sw).failed);

        } catch (IOException | SwitchStateException e) {
            assertEquals("unexpected error thrown",
                    SwitchStateException.class, e.getClass());
        }
    }