TEST(RoleGraphTest, ReAddRole) {
    RoleName roleA("roleA", "dbA");
    RoleName roleB("roleB", "dbB");
    RoleName roleC("roleC", "dbC");

    ActionSet actionsA, actionsB, actionsC;
    actionsA.addAction(ActionType::find);
    actionsB.addAction(ActionType::insert);
    actionsC.addAction(ActionType::update);

    RoleGraph graph;
    ASSERT_OK(graph.createRole(roleA));
    ASSERT_OK(graph.createRole(roleB));
    ASSERT_OK(graph.createRole(roleC));

    ASSERT_OK(graph.addPrivilegeToRole(roleA, Privilege(dbResource, actionsA)));
    ASSERT_OK(graph.addPrivilegeToRole(roleB, Privilege(dbResource, actionsB)));
    ASSERT_OK(graph.addPrivilegeToRole(roleC, Privilege(dbResource, actionsC)));

    ASSERT_OK(graph.addRoleToRole(roleA, roleB));
    ASSERT_OK(graph.addRoleToRole(roleB, roleC));  // graph: A <- B <- C

    ASSERT_OK(graph.recomputePrivilegeData());

    // roleA should have privileges from roleB and roleC
    PrivilegeVector privileges = graph.getAllPrivileges(roleA);
    ASSERT_EQUALS(static_cast<size_t>(1), privileges.size());
    ASSERT_TRUE(privileges[0].getActions().contains(ActionType::find));
    ASSERT_TRUE(privileges[0].getActions().contains(ActionType::insert));
    ASSERT_TRUE(privileges[0].getActions().contains(ActionType::update));

    // Now remove roleB from roleA.  B still is a member of C, but A no longer should have
    // privileges from B or C.
    ASSERT_OK(graph.removeRoleFromRole(roleA, roleB));
    ASSERT_OK(graph.recomputePrivilegeData());

    // roleA should no longer have the privileges from roleB or roleC
    privileges = graph.getAllPrivileges(roleA);
    ASSERT_EQUALS(static_cast<size_t>(1), privileges.size());
    ASSERT_TRUE(privileges[0].getActions().contains(ActionType::find));
    ASSERT_FALSE(privileges[0].getActions().contains(ActionType::insert));
    ASSERT_FALSE(privileges[0].getActions().contains(ActionType::update));

    // Change the privileges that roleB grants
    ASSERT_OK(graph.removeAllPrivilegesFromRole(roleB));
    ActionSet newActionsB;
    newActionsB.addAction(ActionType::remove);
    ASSERT_OK(graph.addPrivilegeToRole(roleB, Privilege(dbResource, newActionsB)));

    // Grant roleB back to roleA, make sure roleA has roleB's new privilege but not its old one.
    ASSERT_OK(graph.addRoleToRole(roleA, roleB));
    ASSERT_OK(graph.recomputePrivilegeData());

    privileges = graph.getAllPrivileges(roleA);
    ASSERT_EQUALS(static_cast<size_t>(1), privileges.size());
    ASSERT_TRUE(privileges[0].getActions().contains(ActionType::find));
    ASSERT_TRUE(privileges[0].getActions().contains(
        ActionType::update));  // should get roleC's actions again
    ASSERT_TRUE(privileges[0].getActions().contains(
        ActionType::remove));  // roleB should grant this to roleA
    ASSERT_FALSE(privileges[0].getActions().contains(
        ActionType::insert));  // no roles have this action anymore

    // Now delete roleB completely.  A should once again lose the privileges from both B and C.
    ASSERT_OK(graph.deleteRole(roleB));
    ASSERT_OK(graph.recomputePrivilegeData());

    // roleA should no longer have the privileges from roleB or roleC
    privileges = graph.getAllPrivileges(roleA);
    ASSERT_EQUALS(static_cast<size_t>(1), privileges.size());
    ASSERT_TRUE(privileges[0].getActions().contains(ActionType::find));
    ASSERT_FALSE(privileges[0].getActions().contains(ActionType::update));
    ASSERT_FALSE(privileges[0].getActions().contains(ActionType::remove));
    ASSERT_FALSE(privileges[0].getActions().contains(ActionType::insert));

    // Now re-create roleB and give it a new privilege, then grant it back to roleA.
    // RoleA should get its new privilege but not roleC's privilege this time nor either of
    // roleB's old privileges.
    ASSERT_OK(graph.createRole(roleB));
    actionsB.removeAllActions();
    actionsB.addAction(ActionType::shutdown);
    ASSERT_OK(graph.addPrivilegeToRole(roleB, Privilege(dbResource, actionsB)));
    ASSERT_OK(graph.addRoleToRole(roleA, roleB));
    ASSERT_OK(graph.recomputePrivilegeData());

    privileges = graph.getAllPrivileges(roleA);
    ASSERT_EQUALS(static_cast<size_t>(1), privileges.size());
    ASSERT_TRUE(privileges[0].getActions().contains(ActionType::find));
    ASSERT_TRUE(privileges[0].getActions().contains(ActionType::shutdown));
    ASSERT_FALSE(privileges[0].getActions().contains(ActionType::update));
    ASSERT_FALSE(privileges[0].getActions().contains(ActionType::remove));
    ASSERT_FALSE(privileges[0].getActions().contains(ActionType::insert));
}