TEST(RoleGraphTest, RecomputePrivilegeData) {
    // We create 4 roles and give each of them a unique privilege.  After that the direct
    // privileges for all the roles are not touched.  The only thing that is changed is the
    // role membership graph, and we test how that affects the set of all transitive privileges
    // for each role.
    RoleName roleA("roleA", "dbA");
    RoleName roleB("roleB", "dbB");
    RoleName roleC("roleC", "dbC");
    RoleName roleD("readWrite", "dbD");  // built-in role

    ActionSet actions;
    actions.addAllActions();

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

    ASSERT_OK(graph.addPrivilegeToRole(roleA, Privilege(dbAResource, actions)));
    ASSERT_OK(graph.addPrivilegeToRole(roleB, Privilege(dbBResource, actions)));
    ASSERT_OK(graph.addPrivilegeToRole(roleC, Privilege(dbCResource, actions)));

    ASSERT_OK(graph.recomputePrivilegeData());

    PrivilegeVector privileges = graph.getAllPrivileges(roleA);
    ASSERT_EQUALS(static_cast<size_t>(1), privileges.size());
    ASSERT_EQUALS(dbAResource, privileges[0].getResourcePattern());

    // At this point we have all 4 roles set up, each with their own privilege, but no
    // roles have been granted to each other.

    ASSERT_OK(graph.addRoleToRole(roleA, roleB));
    // Role graph: A->B
    ASSERT_OK(graph.recomputePrivilegeData());
    privileges = graph.getAllPrivileges(roleA);
    ASSERT_EQUALS(static_cast<size_t>(2), privileges.size());
    ASSERT_EQUALS(dbAResource, privileges[0].getResourcePattern());
    ASSERT_EQUALS(dbBResource, privileges[1].getResourcePattern());

    // Add's roleC's privileges to roleB and make sure roleA gets them as well.
    ASSERT_OK(graph.addRoleToRole(roleB, roleC));
    // Role graph: A->B->C
    ASSERT_OK(graph.recomputePrivilegeData());
    privileges = graph.getAllPrivileges(roleA);
    ASSERT_EQUALS(static_cast<size_t>(3), privileges.size());
    ASSERT_EQUALS(dbAResource, privileges[0].getResourcePattern());
    ASSERT_EQUALS(dbBResource, privileges[1].getResourcePattern());
    ASSERT_EQUALS(dbCResource, privileges[2].getResourcePattern());
    privileges = graph.getAllPrivileges(roleB);
    ASSERT_EQUALS(static_cast<size_t>(2), privileges.size());
    ASSERT_EQUALS(dbBResource, privileges[0].getResourcePattern());
    ASSERT_EQUALS(dbCResource, privileges[1].getResourcePattern());

    // Add's roleD's privileges to roleC and make sure that roleA and roleB get them as well.
    ASSERT_OK(graph.addRoleToRole(roleC, roleD));
    // Role graph: A->B->C->D
    ASSERT_OK(graph.recomputePrivilegeData());
    privileges = graph.getAllPrivileges(roleA);
    const size_t readWriteRolePrivilegeCount = graph.getAllPrivileges(roleD).size();
    ASSERT_EQUALS(readWriteRolePrivilegeCount + 3, privileges.size());
    ASSERT_EQUALS(dbAResource, privileges[0].getResourcePattern());
    ASSERT_EQUALS(dbBResource, privileges[1].getResourcePattern());
    ASSERT_EQUALS(dbCResource, privileges[2].getResourcePattern());
    privileges = graph.getAllPrivileges(roleB);
    ASSERT_EQUALS(readWriteRolePrivilegeCount + 2, privileges.size());
    ASSERT_EQUALS(dbBResource, privileges[0].getResourcePattern());
    ASSERT_EQUALS(dbCResource, privileges[1].getResourcePattern());
    privileges = graph.getAllPrivileges(roleC);
    ASSERT_EQUALS(readWriteRolePrivilegeCount + 1, privileges.size());
    ASSERT_EQUALS(dbCResource, privileges[0].getResourcePattern());

    // Remove roleC from roleB, make sure that roleA then loses both roleC's and roleD's
    // privileges
    ASSERT_OK(graph.removeRoleFromRole(roleB, roleC));
    // Role graph: A->B     C->D
    ASSERT_OK(graph.recomputePrivilegeData());
    privileges = graph.getAllPrivileges(roleA);
    ASSERT_EQUALS(static_cast<size_t>(2), privileges.size());
    ASSERT_EQUALS(dbAResource, privileges[0].getResourcePattern());
    ASSERT_EQUALS(dbBResource, privileges[1].getResourcePattern());
    privileges = graph.getAllPrivileges(roleB);
    ASSERT_EQUALS(static_cast<size_t>(1), privileges.size());
    ASSERT_EQUALS(dbBResource, privileges[0].getResourcePattern());
    privileges = graph.getAllPrivileges(roleC);
    ASSERT_EQUALS(readWriteRolePrivilegeCount + 1, privileges.size());
    ASSERT_EQUALS(dbCResource, privileges[0].getResourcePattern());
    privileges = graph.getAllPrivileges(roleD);
    ASSERT_EQUALS(readWriteRolePrivilegeCount, privileges.size());

    // Make sure direct privileges were untouched
    privileges = graph.getDirectPrivileges(roleA);
    ASSERT_EQUALS(static_cast<size_t>(1), privileges.size());
    ASSERT_EQUALS(dbAResource, privileges[0].getResourcePattern());
    privileges = graph.getDirectPrivileges(roleB);
    ASSERT_EQUALS(static_cast<size_t>(1), privileges.size());
    ASSERT_EQUALS(dbBResource, privileges[0].getResourcePattern());
    privileges = graph.getDirectPrivileges(roleC);
    ASSERT_EQUALS(static_cast<size_t>(1), privileges.size());
    ASSERT_EQUALS(dbCResource, privileges[0].getResourcePattern());
    privileges = graph.getDirectPrivileges(roleD);
    ASSERT_EQUALS(readWriteRolePrivilegeCount, privileges.size());
}