Extend admin-client GroupsResource: Support the query functionality to be used in combination with the parameters first, max and briefRepresentation
Closes #20016
This commit is contained in:
parent
2493f11331
commit
60b838675d
2 changed files with 94 additions and 16 deletions
|
@ -150,4 +150,11 @@ public interface GroupsResource {
|
||||||
@GET
|
@GET
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
List<GroupRepresentation> query(@QueryParam("q") String searchQuery, @QueryParam("populateHierarchy") boolean populateHierarchy);
|
List<GroupRepresentation> query(@QueryParam("q") String searchQuery, @QueryParam("populateHierarchy") boolean populateHierarchy);
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
List<GroupRepresentation> query(@QueryParam("q") String searchQuery,
|
||||||
|
@QueryParam("populateHierarchy") boolean populateHierarchy, @QueryParam("first") Integer first,
|
||||||
|
@QueryParam("max") Integer max, @QueryParam("briefRepresentation") boolean briefRepresentation);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package org.keycloak.testsuite.admin.group;
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||||
|
import static org.hamcrest.Matchers.empty;
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
import static org.hamcrest.Matchers.hasSize;
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
|
import static org.keycloak.testsuite.auth.page.AuthRealm.TEST;
|
||||||
|
@ -13,7 +14,6 @@ import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.hamcrest.Matchers;
|
|
||||||
import org.jboss.arquillian.container.test.api.ContainerController;
|
import org.jboss.arquillian.container.test.api.ContainerController;
|
||||||
import org.jboss.arquillian.test.api.ArquillianResource;
|
import org.jboss.arquillian.test.api.ArquillianResource;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
@ -103,34 +103,34 @@ public class GroupSearchTest extends AbstractGroupTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testQuerySearch() throws Exception {
|
public void querySearch() throws Exception {
|
||||||
configureSearchableAttributes(ATTR_URL_NAME, ATTR_ORG_NAME, ATTR_QUOTES_NAME);
|
configureSearchableAttributes();
|
||||||
try (Creator<GroupResource> groupCreator1 = Creator.create(testRealmResource(), group1);
|
try (Creator<GroupResource> groupCreator1 = Creator.create(testRealmResource(), group1);
|
||||||
Creator<GroupResource> groupCreator2 = Creator.create(testRealmResource(), group2);
|
Creator<GroupResource> groupCreator2 = Creator.create(testRealmResource(), group2);
|
||||||
Creator<GroupResource> groupCreator3 = Creator.create(testRealmResource(), group3)) {
|
Creator<GroupResource> groupCreator3 = Creator.create(testRealmResource(), group3)) {
|
||||||
search(String.format("%s:%s", ATTR_ORG_NAME, ATTR_ORG_VAL), GROUP1);
|
search(buildSearchQuery(ATTR_ORG_NAME, ATTR_ORG_VAL), GROUP1);
|
||||||
search(String.format("%s:%s", ATTR_URL_NAME, ATTR_URL_VAL), GROUP1, GROUP2);
|
search(buildSearchQuery(ATTR_URL_NAME, ATTR_URL_VAL), GROUP1, GROUP2);
|
||||||
search(String.format("%s:%s %s:%s", ATTR_ORG_NAME, ATTR_ORG_VAL, ATTR_URL_NAME, ATTR_URL_VAL),
|
search(buildSearchQuery(ATTR_ORG_NAME, ATTR_ORG_VAL, ATTR_URL_NAME, ATTR_URL_VAL),
|
||||||
GROUP1);
|
GROUP1);
|
||||||
search(String.format("%s:%s %s:%s", ATTR_ORG_NAME, "wrong val", ATTR_URL_NAME, ATTR_URL_VAL));
|
search(buildSearchQuery(ATTR_ORG_NAME, "wrong val", ATTR_URL_NAME, ATTR_URL_VAL));
|
||||||
search(String.format("%s:%s", ATTR_QUOTES_NAME_ESCAPED, ATTR_QUOTES_VAL_ESCAPED), GROUP3);
|
search(buildSearchQuery(ATTR_QUOTES_NAME_ESCAPED, ATTR_QUOTES_VAL_ESCAPED), GROUP3);
|
||||||
|
|
||||||
// "filtered" attribute won't take effect when JPA is used
|
// "filtered" attribute won't take effect when JPA is used
|
||||||
String[] expectedRes = isLegacyJpaStore() ? new String[]{GROUP1, GROUP2} : new String[]{GROUP2};
|
String[] expectedRes = isLegacyJpaStore() ? new String[]{GROUP1, GROUP2} : new String[]{GROUP2};
|
||||||
search(String.format("%s:%s %s:%s", ATTR_URL_NAME, ATTR_URL_VAL, ATTR_FILTERED_NAME, ATTR_FILTERED_VAL), expectedRes);
|
search(buildSearchQuery(ATTR_URL_NAME, ATTR_URL_VAL, ATTR_FILTERED_NAME, ATTR_FILTERED_VAL), expectedRes);
|
||||||
} finally {
|
} finally {
|
||||||
resetSearchableAttributes();
|
resetSearchableAttributes();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNestedGroupQuerySearch() throws Exception {
|
public void nestedGroupQuerySearch() throws Exception {
|
||||||
configureSearchableAttributes(ATTR_URL_NAME, ATTR_ORG_NAME, ATTR_QUOTES_NAME);
|
configureSearchableAttributes();
|
||||||
try (Creator<GroupResource> parentGroupCreator = Creator.create(testRealmResource(), parentGroup)) {
|
try (Creator<GroupResource> parentGroupCreator = Creator.create(testRealmResource(), parentGroup)) {
|
||||||
parentGroupCreator.resource().subGroup(childGroup);
|
parentGroupCreator.resource().subGroup(childGroup);
|
||||||
// query for the child group by org name
|
// query for the child group by org name
|
||||||
GroupsResource search = testRealmResource().groups();
|
GroupsResource search = testRealmResource().groups();
|
||||||
String searchQuery = String.format("%s:%s", ATTR_ORG_NAME, "childOrg");
|
String searchQuery = buildSearchQuery(ATTR_ORG_NAME, "childOrg");
|
||||||
List<GroupRepresentation> found = search.query(searchQuery);
|
List<GroupRepresentation> found = search.query(searchQuery);
|
||||||
|
|
||||||
assertThat(found.size(), is(1));
|
assertThat(found.size(), is(1));
|
||||||
|
@ -145,8 +145,8 @@ public class GroupSearchTest extends AbstractGroupTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNestedGroupQuerySearchNoHierarchy() throws Exception {
|
public void nestedGroupQuerySearchNoHierarchy() throws Exception {
|
||||||
configureSearchableAttributes(ATTR_URL_NAME, ATTR_ORG_NAME, ATTR_QUOTES_NAME);
|
configureSearchableAttributes();
|
||||||
try (Creator<GroupResource> parentGroupCreator = Creator.create(testRealmResource(), parentGroup)) {
|
try (Creator<GroupResource> parentGroupCreator = Creator.create(testRealmResource(), parentGroup)) {
|
||||||
parentGroupCreator.resource().subGroup(childGroup);
|
parentGroupCreator.resource().subGroup(childGroup);
|
||||||
|
|
||||||
|
@ -156,7 +156,7 @@ public class GroupSearchTest extends AbstractGroupTest {
|
||||||
|
|
||||||
// query for the child group by org name
|
// query for the child group by org name
|
||||||
GroupsResource search = testRealmResource().groups();
|
GroupsResource search = testRealmResource().groups();
|
||||||
String searchQuery = String.format("%s:%s", ATTR_ORG_NAME, "childOrg");
|
String searchQuery = buildSearchQuery(ATTR_ORG_NAME, "childOrg");
|
||||||
List<GroupRepresentation> found = search.query(searchQuery, false);
|
List<GroupRepresentation> found = search.query(searchQuery, false);
|
||||||
|
|
||||||
assertThat(found.size(), is(1));
|
assertThat(found.size(), is(1));
|
||||||
|
@ -169,6 +169,50 @@ public class GroupSearchTest extends AbstractGroupTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void queryPaging() throws Exception {
|
||||||
|
configureSearchableAttributes();
|
||||||
|
try (Creator<GroupResource> group1Creator = Creator.create(testRealmResource(), group1);
|
||||||
|
Creator<GroupResource> group2Creator = Creator.create(testRealmResource(), group2)) {
|
||||||
|
String searchQuery = buildSearchQuery(ATTR_URL_NAME, ATTR_URL_VAL);
|
||||||
|
|
||||||
|
List<GroupRepresentation> firstPage = testRealmResource().groups()
|
||||||
|
.query(searchQuery, true, 0, 1, true);
|
||||||
|
assertThat(firstPage, hasSize(1));
|
||||||
|
GroupRepresentation firstGroup = firstPage.get(0);
|
||||||
|
assertThat(firstGroup.getName(), is(equalTo(GROUP1)));
|
||||||
|
|
||||||
|
List<GroupRepresentation> secondPage = testRealmResource().groups()
|
||||||
|
.query(searchQuery, true, 1, 1, true);
|
||||||
|
assertThat(secondPage, hasSize(1));
|
||||||
|
GroupRepresentation secondGroup = secondPage.get(0);
|
||||||
|
assertThat(secondGroup.getName(), is(equalTo(GROUP2)));
|
||||||
|
|
||||||
|
List<GroupRepresentation> thirdPage = testRealmResource().groups()
|
||||||
|
.query(searchQuery, true, 2, 1, true);
|
||||||
|
assertThat(thirdPage, is(empty()));
|
||||||
|
} finally {
|
||||||
|
resetSearchableAttributes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void queryFullRepresentation() throws Exception {
|
||||||
|
configureSearchableAttributes();
|
||||||
|
try (Creator<GroupResource> group1Creator = Creator.create(testRealmResource(), group1)) {
|
||||||
|
List<GroupRepresentation> found = testRealmResource().groups()
|
||||||
|
.query(buildSearchQuery(ATTR_ORG_NAME, ATTR_ORG_VAL), true, 0, 100, false);
|
||||||
|
|
||||||
|
assertThat(found, hasSize(1));
|
||||||
|
GroupRepresentation group = found.get(0);
|
||||||
|
assertThat(group.getName(), is(equalTo(GROUP1)));
|
||||||
|
// attributes are not contained in group representation, only in full representation
|
||||||
|
assertThat(group.getAttributes(), is(equalTo(group1.getAttributes())));
|
||||||
|
} finally {
|
||||||
|
resetSearchableAttributes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void search(String searchQuery, String... expectedGroupIds) {
|
private void search(String searchQuery, String... expectedGroupIds) {
|
||||||
GroupsResource search = testRealmResource().groups();
|
GroupsResource search = testRealmResource().groups();
|
||||||
List<String> found = search.query(searchQuery).stream()
|
List<String> found = search.query(searchQuery).stream()
|
||||||
|
@ -178,7 +222,8 @@ public class GroupSearchTest extends AbstractGroupTest {
|
||||||
assertThat(found, containsInAnyOrder(expectedGroupIds));
|
assertThat(found, containsInAnyOrder(expectedGroupIds));
|
||||||
}
|
}
|
||||||
|
|
||||||
void configureSearchableAttributes(String... searchableAttributes) throws Exception {
|
void configureSearchableAttributes() throws Exception {
|
||||||
|
String[] searchableAttributes = new String[]{ATTR_URL_NAME, ATTR_ORG_NAME, ATTR_QUOTES_NAME};
|
||||||
log.infov("Configuring searchableAttributes");
|
log.infov("Configuring searchableAttributes");
|
||||||
if (suiteContext.getAuthServerInfo().isUndertow()) {
|
if (suiteContext.getAuthServerInfo().isUndertow()) {
|
||||||
controller.stop(suiteContext.getAuthServerInfo().getQualifier());
|
controller.stop(suiteContext.getAuthServerInfo().getQualifier());
|
||||||
|
@ -217,6 +262,32 @@ public class GroupSearchTest extends AbstractGroupTest {
|
||||||
reconnectAdminClient();
|
reconnectAdminClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String buildSearchQuery(String firstAttrName, String firstAttrValue, String... furtherAttrKeysAndValues) {
|
||||||
|
if (furtherAttrKeysAndValues.length % 2 != 0) {
|
||||||
|
throw new IllegalArgumentException("Invalid length of furtherAttrKeysAndValues. Must be even, but is: " + furtherAttrKeysAndValues.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
String keyValueSep = ":";
|
||||||
|
String attributesSep = " ";
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append(firstAttrName).append(keyValueSep).append(firstAttrValue);
|
||||||
|
|
||||||
|
if (furtherAttrKeysAndValues.length != 0) {
|
||||||
|
for (int i = 0; i < furtherAttrKeysAndValues.length; i++) {
|
||||||
|
if (i % 2 == 0) {
|
||||||
|
sb.append(attributesSep);
|
||||||
|
} else {
|
||||||
|
sb.append(keyValueSep);
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.append(furtherAttrKeysAndValues[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isLegacyJpaStore() {
|
private boolean isLegacyJpaStore() {
|
||||||
return keycloakUsingProviderWithId(GroupProvider.class, "jpa");
|
return keycloakUsingProviderWithId(GroupProvider.class, "jpa");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue