Do not store undefined values in store

Closes #10744
This commit is contained in:
Michal Hajas 2022-03-16 16:10:10 +01:00 committed by Hynek Mlnařík
parent 99f27497f4
commit c18a682f50
14 changed files with 409 additions and 24 deletions

View file

@ -215,6 +215,17 @@ public abstract class AbstractGenerateEntityImplementationsProcessor extends Abs
return "deepClone(" + parameterName + ")"; return "deepClone(" + parameterName + ")";
} }
protected String removeUndefined(TypeMirror fieldType, String parameterName) {
TypeElement typeElement = elements.getTypeElement(types.erasure(fieldType).toString());
boolean isMapType = isMapType(typeElement);
return parameterName + (isMapType ? ".values()" : "") + ".removeIf(org.keycloak.models.map.common.UndefinedValuesUtils::isUndefined)";
}
protected String isUndefined(String parameterName) {
return "org.keycloak.models.map.common.UndefinedValuesUtils.isUndefined(" + parameterName + ")";
}
protected boolean isEnumType(TypeMirror fieldType) { protected boolean isEnumType(TypeMirror fieldType) {
return types.asElement(fieldType).getKind() == ElementKind.ENUM; return types.asElement(fieldType).getKind() == ElementKind.ENUM;
} }

View file

@ -426,16 +426,26 @@ public class GenerateEntityImplementationsProcessor extends AbstractGenerateEnti
if (! isImmutableFinalType(fieldType)) { if (! isImmutableFinalType(fieldType)) {
pw.println(" p0 = " + deepClone(firstParameterType, "p0") + ";"); pw.println(" p0 = " + deepClone(firstParameterType, "p0") + ";");
} }
if (isCollection(firstParameterType)) {
pw.println(" if (p0 != null) {");
pw.println(" " + removeUndefined(firstParameterType, "p0") + ";");
pw.println(" if (" + isUndefined("p0") + ") p0 = null;");
pw.println(" }");
}
pw.println(" updated |= ! Objects.equals(" + fieldName + ", p0);"); pw.println(" updated |= ! Objects.equals(" + fieldName + ", p0);");
pw.println(" " + fieldName + " = p0;"); pw.println(" " + fieldName + " = p0;");
pw.println(" }"); pw.println(" }");
return true; return true;
case COLLECTION_ADD: case COLLECTION_ADD:
pw.println(" @SuppressWarnings(\"unchecked\") @Override public " + method.getReturnType() + " " + method.getSimpleName() + "(" + firstParameterType + " p0) {"); pw.println(" @SuppressWarnings(\"unchecked\") @Override public " + method.getReturnType() + " " + method.getSimpleName() + "(" + firstParameterType + " p0) {");
pw.println(" if (" + fieldName + " == null) { " + fieldName + " = " + interfaceToImplementation(typeElement, "") + "; }");
if (! isImmutableFinalType(firstParameterType)) { if (! isImmutableFinalType(firstParameterType)) {
pw.println(" p0 = " + deepClone(firstParameterType, "p0") + ";"); pw.println(" p0 = " + deepClone(firstParameterType, "p0") + ";");
} }
if (isCollection(firstParameterType)) {
pw.println(" if (p0 != null) " + removeUndefined(firstParameterType, "p0") + ";");
}
pw.println(" if (" + isUndefined("p0") + ") return;");
pw.println(" if (" + fieldName + " == null) { " + fieldName + " = " + interfaceToImplementation(typeElement, "") + "; }");
if (isSetType(typeElement)) { if (isSetType(typeElement)) {
pw.println(" updated |= " + fieldName + ".add(p0);"); pw.println(" updated |= " + fieldName + ".add(p0);");
} else { } else {
@ -456,10 +466,16 @@ public class GenerateEntityImplementationsProcessor extends AbstractGenerateEnti
case MAP_ADD: case MAP_ADD:
TypeMirror secondParameterType = method.getParameters().get(1).asType(); TypeMirror secondParameterType = method.getParameters().get(1).asType();
pw.println(" @SuppressWarnings(\"unchecked\") @Override public " + method.getReturnType() + " " + method.getSimpleName() + "(" + firstParameterType + " p0, " + secondParameterType + " p1) {"); pw.println(" @SuppressWarnings(\"unchecked\") @Override public " + method.getReturnType() + " " + method.getSimpleName() + "(" + firstParameterType + " p0, " + secondParameterType + " p1) {");
pw.println(" if (" + fieldName + " == null) { " + fieldName + " = " + interfaceToImplementation(typeElement, "") + "; }");
if (! isImmutableFinalType(secondParameterType)) { if (! isImmutableFinalType(secondParameterType)) {
pw.println(" p1 = " + deepClone(secondParameterType, "p1") + ";"); pw.println(" p1 = " + deepClone(secondParameterType, "p1") + ";");
} }
if (isCollection(secondParameterType)) {
pw.println(" if (p1 != null) " + removeUndefined(secondParameterType, "p1") + ";");
}
pw.println(" boolean valueUndefined = " + isUndefined("p1") + ";");
pw.println(" if (valueUndefined) { if (" + fieldName + " != null) { updated |= " + fieldName + ".remove(p0) != null; } return; }");
pw.println(" if (" + fieldName + " == null) { " + fieldName + " = " + interfaceToImplementation(typeElement, "") + "; }");
pw.println(" Object v = " + fieldName + ".put(p0, p1);"); pw.println(" Object v = " + fieldName + ".put(p0, p1);");
pw.println(" updated |= ! Objects.equals(v, p1);"); pw.println(" updated |= ! Objects.equals(v, p1);");
pw.println(" }"); pw.println(" }");

View file

@ -334,6 +334,9 @@ public class GenerateHotRodEntityImplementationsProcessor extends AbstractGenera
if (! isImmutableFinalType(firstParameterType)) { if (! isImmutableFinalType(firstParameterType)) {
pw.println(" p0 = " + deepClone(firstParameterType, "p0") + ";"); pw.println(" p0 = " + deepClone(firstParameterType, "p0") + ";");
} }
if (isCollection(firstParameterType)) {
pw.println(" if (p0 != null) " + removeUndefined(firstParameterType, "p0") + ";");
}
pw.println(" " + hotRodFieldType.toString() + " migrated = " + migrateToType(hotRodFieldType, firstParameterType, "p0") + ";"); pw.println(" " + hotRodFieldType.toString() + " migrated = " + migrateToType(hotRodFieldType, firstParameterType, "p0") + ";");
pw.println(" " + hotRodEntityField("updated") + " |= ! Objects.equals(" + hotRodEntityField(fieldName) + ", migrated);"); pw.println(" " + hotRodEntityField("updated") + " |= ! Objects.equals(" + hotRodEntityField(fieldName) + ", migrated);");
pw.println(" " + hotRodEntityField(fieldName) + " = migrated;"); pw.println(" " + hotRodEntityField(fieldName) + " = migrated;");
@ -342,10 +345,14 @@ public class GenerateHotRodEntityImplementationsProcessor extends AbstractGenera
case COLLECTION_ADD: case COLLECTION_ADD:
TypeMirror collectionItemType = getGenericsDeclaration(hotRodFieldType).get(0); TypeMirror collectionItemType = getGenericsDeclaration(hotRodFieldType).get(0);
pw.println(" @SuppressWarnings(\"unchecked\") @Override public " + method.getReturnType() + " " + method.getSimpleName() + "(" + firstParameterType + " p0) {"); pw.println(" @SuppressWarnings(\"unchecked\") @Override public " + method.getReturnType() + " " + method.getSimpleName() + "(" + firstParameterType + " p0) {");
pw.println(" if (" + hotRodEntityField(fieldName) + " == null) { " + hotRodEntityField(fieldName) + " = " + interfaceToImplementation(typeElement, "") + "; }");
if (! isImmutableFinalType(firstParameterType)) { if (! isImmutableFinalType(firstParameterType)) {
pw.println(" p0 = " + deepClone(firstParameterType, "p0") + ";"); pw.println(" p0 = " + deepClone(firstParameterType, "p0") + ";");
} }
if (isCollection(firstParameterType)) {
pw.println(" if (p0 != null) " + removeUndefined(firstParameterType, "p0") + ";");
}
pw.println(" if (" + isUndefined("p0") + ") return;");
pw.println(" if (" + hotRodEntityField(fieldName) + " == null) { " + hotRodEntityField(fieldName) + " = " + interfaceToImplementation(typeElement, "") + "; }");
pw.println(" " + collectionItemType.toString() + " migrated = " + migrateToType(collectionItemType, firstParameterType, "p0") + ";"); pw.println(" " + collectionItemType.toString() + " migrated = " + migrateToType(collectionItemType, firstParameterType, "p0") + ";");
if (isSetType(typeElement)) { if (isSetType(typeElement)) {
pw.println(" " + hotRodEntityField("updated") + " |= " + hotRodEntityField(fieldName) + ".add(migrated);"); pw.println(" " + hotRodEntityField("updated") + " |= " + hotRodEntityField(fieldName) + ".add(migrated);");
@ -380,10 +387,13 @@ public class GenerateHotRodEntityImplementationsProcessor extends AbstractGenera
TypeMirror secondParameterType = method.getParameters().get(1).asType(); TypeMirror secondParameterType = method.getParameters().get(1).asType();
pw.println(" @SuppressWarnings(\"unchecked\") @Override public " + method.getReturnType() + " " + method.getSimpleName() + "(" + firstParameterType + " p0, " + secondParameterType + " p1) {"); pw.println(" @SuppressWarnings(\"unchecked\") @Override public " + method.getReturnType() + " " + method.getSimpleName() + "(" + firstParameterType + " p0, " + secondParameterType + " p1) {");
pw.println(" if (" + hotRodEntityField(fieldName) + " == null) { " + hotRodEntityField(fieldName) + " = " + interfaceToImplementation((TypeElement) types.asElement(types.erasure(hotRodFieldType)), "") + "; }"); pw.println(" if (" + hotRodEntityField(fieldName) + " == null) { " + hotRodEntityField(fieldName) + " = " + interfaceToImplementation((TypeElement) types.asElement(types.erasure(hotRodFieldType)), "") + "; }");
pw.println(" boolean valueUndefined = p1 == null" + (isCollection(secondParameterType) ? " || p1.isEmpty()" : "") + ";");
if (! isImmutableFinalType(secondParameterType)) { if (! isImmutableFinalType(secondParameterType)) {
pw.println(" p1 = " + deepClone(secondParameterType, "p1") + ";"); pw.println(" p1 = " + deepClone(secondParameterType, "p1") + ";");
} }
if (isCollection(secondParameterType)) {
pw.println(" if (p1 != null) " + removeUndefined(secondParameterType, "p1") + ";");
}
pw.println(" boolean valueUndefined = " + isUndefined("p1") + ";");
pw.println(" " + hotRodEntityField("updated") + " |= " + hotRodUtils.getQualifiedName().toString() + ".removeFromSetByMapKey(" pw.println(" " + hotRodEntityField("updated") + " |= " + hotRodUtils.getQualifiedName().toString() + ".removeFromSetByMapKey("
+ hotRodEntityField(fieldName) + ", " + hotRodEntityField(fieldName) + ", "
+ "p0, " + "p0, "

View file

@ -17,6 +17,7 @@
package org.keycloak.models.map.client; package org.keycloak.models.map.client;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
@ -50,8 +51,8 @@ public class MapProtocolMapperUtils {
res.setId(entity.getId()); res.setId(entity.getId());
res.setName(entity.getName()); res.setName(entity.getName());
res.setProtocolMapper(entity.getProtocolMapper()); res.setProtocolMapper(entity.getProtocolMapper());
res.setConfig(entity.getConfig()); Map<String, String> config = entity.getConfig();
res.setConfig(config == null ? new HashMap<>(): new HashMap<>(config));
res.setProtocol(protocol); res.setProtocol(protocol);
return res; return res;
} }

View file

@ -0,0 +1,67 @@
/*
* Copyright 2022 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.models.map.common;
import java.util.Collection;
import java.util.Map;
/**
* This Util class defines conditions when objects can be considered undefined
* <br/>
* <br/>
* For example:
* <ul>
* <li>{@link String} is undefined if it is {@code null} or {@code empty}</li>
* <li>{@link Collection} is undefined if it is {@code null}, {@code empty} or all items are undefined</li>
* <li>{@link Map} is undefined if it is {@code null}, {@code empty}, or all values are undefined</li>
* </ul>
*/
public class UndefinedValuesUtils {
/**
* Decides whether the {@link Object o} is defined or not
*
* @param o object to check
* @return true when the {@link Object o} is undefined, false otherwise
*/
public static boolean isUndefined(Object o) {
if (o == null) {
return true;
} else if (o instanceof Collection) {
return isUndefinedCollection((Collection<?>) o);
} else if (o instanceof Map) {
return isUndefinedMap((Map<?, ?>) o);
} else if (o instanceof String) {
return isUndefinedString((String) o);
} else {
return false;
}
}
private static boolean isUndefinedCollection(Collection<?> collection) {
return collection.isEmpty() || collection.stream().allMatch(UndefinedValuesUtils::isUndefined);
}
private static boolean isUndefinedMap(Map<?, ?> map) {
return map.isEmpty() || map.values().stream().allMatch(UndefinedValuesUtils::isUndefined);
}
private static boolean isUndefinedString(String str) {
return str.trim().isEmpty();
}
}

View file

@ -438,6 +438,7 @@ public interface MapRealmEntity extends UpdatableEntity, AbstractEntity, EntityW
Map<String, String> getBrowserSecurityHeaders(); Map<String, String> getBrowserSecurityHeaders();
void setBrowserSecurityHeaders(Map<String, String> headers); void setBrowserSecurityHeaders(Map<String, String> headers);
void setBrowserSecurityHeader(String name, String value);
Map<String, String> getSmtpConfig(); Map<String, String> getSmtpConfig();
void setSmtpConfig(Map<String, String> smtpConfig); void setSmtpConfig(Map<String, String> smtpConfig);

View file

@ -53,7 +53,7 @@ public interface MapComponentEntity extends UpdatableEntity, AbstractEntity {
model.setSubType(entity.getSubType()); model.setSubType(entity.getSubType());
model.setParentId(entity.getParentId()); model.setParentId(entity.getParentId());
Map<String, List<String>> config = entity.getConfig(); Map<String, List<String>> config = entity.getConfig();
model.setConfig(config == null ? null : new MultivaluedHashMap<>(config)); model.setConfig(config == null ? new MultivaluedHashMap<>() : new MultivaluedHashMap<>(config));
return model; return model;
} }

View file

@ -46,7 +46,7 @@ public interface MapIdentityProviderEntity extends UpdatableEntity, AbstractEnti
entity.setLinkOnly(model.isLinkOnly()); entity.setLinkOnly(model.isLinkOnly());
entity.setAddReadTokenRoleOnCreate(model.isAddReadTokenRoleOnCreate()); entity.setAddReadTokenRoleOnCreate(model.isAddReadTokenRoleOnCreate());
entity.setAuthenticateByDefault(model.isAuthenticateByDefault()); entity.setAuthenticateByDefault(model.isAuthenticateByDefault());
entity.setConfig(model.getConfig() == null ? null : new HashMap<>(model.getConfig())); entity.setConfig(model.getConfig());
return entity; return entity;
} }
@ -71,7 +71,8 @@ public interface MapIdentityProviderEntity extends UpdatableEntity, AbstractEnti
model.setAddReadTokenRoleOnCreate(addReadTokenRoleOnCreate == null ? false : addReadTokenRoleOnCreate); model.setAddReadTokenRoleOnCreate(addReadTokenRoleOnCreate == null ? false : addReadTokenRoleOnCreate);
Boolean authenticateByDefault = entity.isAuthenticateByDefault(); Boolean authenticateByDefault = entity.isAuthenticateByDefault();
model.setAuthenticateByDefault(authenticateByDefault == null ? false : authenticateByDefault); model.setAuthenticateByDefault(authenticateByDefault == null ? false : authenticateByDefault);
model.setConfig(entity.getConfig() == null ? null : new HashMap<>(entity.getConfig())); Map<String, String> config = entity.getConfig();
model.setConfig(config == null ? new HashMap<>() : new HashMap<>(config));
return model; return model;
} }

View file

@ -38,7 +38,7 @@ public interface MapIdentityProviderMapperEntity extends UpdatableEntity, Abstra
entity.setName(model.getName()); entity.setName(model.getName());
entity.setIdentityProviderAlias(model.getIdentityProviderAlias()); entity.setIdentityProviderAlias(model.getIdentityProviderAlias());
entity.setIdentityProviderMapper(model.getIdentityProviderMapper()); entity.setIdentityProviderMapper(model.getIdentityProviderMapper());
entity.setConfig(model.getConfig() == null ? null : new HashMap<>(model.getConfig())); entity.setConfig(model.getConfig());
return entity; return entity;
} }
@ -49,7 +49,8 @@ public interface MapIdentityProviderMapperEntity extends UpdatableEntity, Abstra
model.setName(entity.getName()); model.setName(entity.getName());
model.setIdentityProviderAlias(entity.getIdentityProviderAlias()); model.setIdentityProviderAlias(entity.getIdentityProviderAlias());
model.setIdentityProviderMapper(entity.getIdentityProviderMapper()); model.setIdentityProviderMapper(entity.getIdentityProviderMapper());
model.setConfig(entity.getConfig() == null ? null : new HashMap<>(entity.getConfig())); Map<String, String> config = entity.getConfig();
model.setConfig(config == null ? new HashMap<>() : new HashMap<>(config));
return model; return model;
} }

View file

@ -58,7 +58,8 @@ public interface MapRequiredActionProviderEntity extends UpdatableEntity, Abstra
model.setEnabled(enabled == null ? false : enabled); model.setEnabled(enabled == null ? false : enabled);
Boolean defaultAction = entity.isDefaultAction(); Boolean defaultAction = entity.isDefaultAction();
model.setDefaultAction(defaultAction == null ? false : defaultAction); model.setDefaultAction(defaultAction == null ? false : defaultAction);
model.setConfig(entity.getConfig()); Map<String, String> config = entity.getConfig();
model.setConfig(config == null ? new HashMap<>() : new HashMap<>(config));
return model; return model;
} }

View file

@ -42,7 +42,7 @@ public interface MapWebAuthnPolicyEntity extends UpdatableEntity {
entity.setUserVerificationRequirement(model.getUserVerificationRequirement()); entity.setUserVerificationRequirement(model.getUserVerificationRequirement());
entity.setCreateTimeout(model.getCreateTimeout()); entity.setCreateTimeout(model.getCreateTimeout());
entity.setAvoidSameAuthenticatorRegister(model.isAvoidSameAuthenticatorRegister()); entity.setAvoidSameAuthenticatorRegister(model.isAvoidSameAuthenticatorRegister());
entity.setAcceptableAaguids(model.getAcceptableAaguids() == null ? null : new LinkedList<>(model.getAcceptableAaguids())); entity.setAcceptableAaguids(model.getAcceptableAaguids());
return entity; return entity;
} }
@ -58,7 +58,8 @@ public interface MapWebAuthnPolicyEntity extends UpdatableEntity {
model.setUserVerificationRequirement(entity.getUserVerificationRequirement()); model.setUserVerificationRequirement(entity.getUserVerificationRequirement());
model.setCreateTimeout(entity.getCreateTimeout()); model.setCreateTimeout(entity.getCreateTimeout());
model.setAvoidSameAuthenticatorRegister(entity.isAvoidSameAuthenticatorRegister()); model.setAvoidSameAuthenticatorRegister(entity.isAvoidSameAuthenticatorRegister());
model.setAcceptableAaguids(entity.getAcceptableAaguids() == null ? null : new LinkedList<>(entity.getAcceptableAaguids())); List<String> acceptableAaguids = entity.getAcceptableAaguids();
model.setAcceptableAaguids(acceptableAaguids == null ? new LinkedList<>() : new LinkedList<>(acceptableAaguids));
return model; return model;
} }

View file

@ -19,6 +19,8 @@ package org.keycloak.models.map.client;
import org.keycloak.models.map.common.DeepCloner; import org.keycloak.models.map.common.DeepCloner;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map;
import org.junit.Test; import org.junit.Test;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.contains;
@ -86,9 +88,10 @@ public class MapClientEntityClonerTest {
newInstance.setAttribute("attr", Arrays.asList("aa", "bb", "cc")); newInstance.setAttribute("attr", Arrays.asList("aa", "bb", "cc"));
MapProtocolMapperEntity pmm = new MapProtocolMapperEntityImpl(); MapProtocolMapperEntity pmm = new MapProtocolMapperEntityImpl();
pmm.setId("pmm-id"); pmm.setId("pmm-id");
pmm.setConfig(new HashMap<>()); Map<String, String> config = new HashMap<>();
pmm.getConfig().put("key1", "value1"); config.put("key1", "value1");
pmm.getConfig().put("key2", "value2"); config.put("key2", "value2");
pmm.setConfig(config);
newInstance.setProtocolMapper("pmm-id", pmm); newInstance.setProtocolMapper("pmm-id", pmm);
newInstance.setAttribute("attr", Arrays.asList("aa", "bb", "cc")); newInstance.setAttribute("attr", Arrays.asList("aa", "bb", "cc"));
@ -122,9 +125,11 @@ public class MapClientEntityClonerTest {
newInstance.setAttribute("attr", Arrays.asList("aa", "bb", "cc")); newInstance.setAttribute("attr", Arrays.asList("aa", "bb", "cc"));
MapProtocolMapperEntity pmm = new MapProtocolMapperEntityImpl(); MapProtocolMapperEntity pmm = new MapProtocolMapperEntityImpl();
pmm.setId("pmm-id"); pmm.setId("pmm-id");
pmm.setConfig(new HashMap<>()); Map<String, String> config = new HashMap<>();
pmm.getConfig().put("key1", "value1"); config.put("key1", "value1");
pmm.getConfig().put("key2", "value2"); config.put("key2", "value2");
pmm.setConfig(config);
newInstance.setProtocolMapper("pmm-id", pmm); newInstance.setProtocolMapper("pmm-id", pmm);
newInstance.setAttribute("attr", Arrays.asList("aa", "bb", "cc")); newInstance.setAttribute("attr", Arrays.asList("aa", "bb", "cc"));

View file

@ -0,0 +1,267 @@
/*
* Copyright 2022 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.models.map.realm;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.aMapWithSize;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.anEmptyMap;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.hasEntry;
import static org.hamcrest.Matchers.hasKey;
public class RealmEntityUndefinedValuesTest {
public MapRealmEntity newMapRealmEntity() {
return new MapRealmEntityImpl();
}
@Test
public void testUndefinedValuesToCollection() {
// setup
MapRealmEntity realmEntity = newMapRealmEntity();
{
// when
realmEntity.setEventsListeners(null);
// then
assertThat(realmEntity.getEventsListeners(), nullValue());
}
{
// when
realmEntity.setEventsListeners(Collections.emptySet());
// then
assertThat(realmEntity.getEventsListeners(), nullValue());
}
{
// when
realmEntity.setEventsListeners(Collections.singleton(null));
// then
assertThat(realmEntity.getEventsListeners(), nullValue());
}
{
// when
realmEntity.setEventsListeners(Collections.singleton("listener1"));
// then
assertThat(realmEntity.getEventsListeners(), contains("listener1"));
}
{
// when
realmEntity.setEventsListeners(Collections.emptySet());
// then
assertThat(realmEntity.getEventsListeners(), nullValue());
}
{
// when
realmEntity.addOptionalClientScopeId(null);
// then
assertThat(realmEntity.getOptionalClientScopeIds(), nullValue());
}
{
// when
realmEntity.addOptionalClientScopeId("id1");
// then
assertThat(realmEntity.getOptionalClientScopeIds(), notNullValue());
assertThat(realmEntity.getOptionalClientScopeIds(), contains("id1"));
}
{
// when
realmEntity.addOptionalClientScopeId(null);
// then
assertThat(realmEntity.getOptionalClientScopeIds(), notNullValue());
assertThat(realmEntity.getOptionalClientScopeIds(), contains("id1"));
}
}
@Test
public void testAddUndefinedValuesToMapStringString() {
// setup
MapRealmEntity realmEntity = newMapRealmEntity();
Map<String, String> headers = new HashMap<>();
{
// when
realmEntity.setBrowserSecurityHeaders(Collections.emptyMap());
// then
assertThat(realmEntity.getBrowserSecurityHeaders(), nullValue());
}
{
// when
headers.put("key1", null);
realmEntity.setBrowserSecurityHeaders(headers);
// then
assertThat(realmEntity.getBrowserSecurityHeaders(), nullValue());
}
{
// when
headers.put("key1", "value1");
realmEntity.setBrowserSecurityHeaders(headers);
// then
assertThat(realmEntity.getBrowserSecurityHeaders(), notNullValue());
assertThat(realmEntity.getBrowserSecurityHeaders(), allOf(aMapWithSize(1), hasEntry(equalTo("key1"), equalTo("value1"))));
}
{
// when
headers.put("key2", null);
realmEntity.setBrowserSecurityHeaders(headers);
// then
assertThat(realmEntity.getBrowserSecurityHeaders(), notNullValue());
assertThat(realmEntity.getBrowserSecurityHeaders(), allOf(aMapWithSize(1), hasEntry(equalTo("key1"), equalTo("value1"))));
}
{
// when
realmEntity.setBrowserSecurityHeaders(Collections.emptyMap());
// then
assertThat(realmEntity.getBrowserSecurityHeaders(), nullValue());
}
{
// when
realmEntity.setBrowserSecurityHeader("key1", null);
// then
assertThat(realmEntity.getBrowserSecurityHeaders(), nullValue());
}
{
// when
realmEntity.setBrowserSecurityHeader("key1", "value1");
// then
assertThat(realmEntity.getBrowserSecurityHeaders(), allOf(aMapWithSize(1), hasEntry(equalTo("key1"), equalTo("value1"))));
}
{
// when
realmEntity.setBrowserSecurityHeader("key2", null);
// then
assertThat(realmEntity.getBrowserSecurityHeaders(), allOf(aMapWithSize(1), hasEntry(equalTo("key1"), equalTo("value1"))));
}
{
// when
realmEntity.setBrowserSecurityHeader("key1", null);
// then
// TODO: Should we set map to null if we remove last entry by calling set*(key, null) method?
assertThat(realmEntity.getBrowserSecurityHeaders(), anEmptyMap());
}
}
@Test
public void testAddUndefinedValuesToMapStringList() {
MapRealmEntity realmEntity = newMapRealmEntity();
Map<String, List<String>> attributes = new HashMap<>();
{
// when
attributes.put("key1", Collections.emptyList());
realmEntity.setAttributes(attributes);
// then
assertThat(realmEntity.getAttributes(), nullValue());
}
{
// when
attributes.put("key1", Collections.singletonList(null));
realmEntity.setAttributes(attributes);
// then
assertThat(realmEntity.getAttributes(), nullValue());
}
{
// when
attributes.put("key1", Arrays.asList(null, null, null));
realmEntity.setAttributes(attributes);
// then
assertThat(realmEntity.getAttributes(), nullValue());
}
}
@Test
public void testAddUndefinedValuesToMapStringMap() {
MapRealmEntity realmEntity = newMapRealmEntity();
Map<String, String> localizationTexts = new HashMap<>();
{
// when
realmEntity.setLocalizationText("en", Collections.emptyMap());
// then
assertThat(realmEntity.getLocalizationText("en"), nullValue());
assertThat(realmEntity.getLocalizationTexts(), nullValue());
}
{
// when
realmEntity.setLocalizationText("en", Collections.singletonMap("key1", null));
// then
assertThat(realmEntity.getLocalizationText("en"), nullValue());
assertThat(realmEntity.getLocalizationTexts(), nullValue());
}
{
// when
realmEntity.setLocalizationText("en", Collections.singletonMap("key1", "value1"));
// then
assertThat(realmEntity.getLocalizationTexts(), allOf(aMapWithSize(1), hasKey("en")));
assertThat(realmEntity.getLocalizationText("en"), allOf(aMapWithSize(1), hasEntry(equalTo("key1"), equalTo("value1"))));
}
{
// when
localizationTexts.put("key1", "value1");
localizationTexts.put("key2", null);
realmEntity.setLocalizationText("en", localizationTexts);
// then
assertThat(realmEntity.getLocalizationTexts(), allOf(aMapWithSize(1), hasKey("en")));
assertThat(realmEntity.getLocalizationText("en"), allOf(aMapWithSize(1), hasEntry(equalTo("key1"), equalTo("value1"))));
}
{
// when
localizationTexts.put("key1", null);
localizationTexts.put("key2", null);
realmEntity.setLocalizationText("en", localizationTexts);
// then
assertThat(realmEntity.getLocalizationTexts(), anEmptyMap());
assertThat(realmEntity.getLocalizationText("en"), nullValue());
}
}
}

View file

@ -61,9 +61,12 @@ import java.util.Map;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.hamcrest.CoreMatchers.anyOf;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import static org.keycloak.testsuite.Assert.assertNames; import static org.keycloak.testsuite.Assert.assertNames;
@ -698,7 +701,7 @@ public class ClientScopeTest extends AbstractClientTest {
scopeRep = clientScopes().get(scopeDefId).toRepresentation(); scopeRep = clientScopes().get(scopeDefId).toRepresentation();
assertEquals("non-dynamic-scope-def", scopeRep.getName()); assertEquals("non-dynamic-scope-def", scopeRep.getName());
assertEquals("false", scopeRep.getAttributes().get(ClientScopeModel.IS_DYNAMIC_SCOPE)); assertEquals("false", scopeRep.getAttributes().get(ClientScopeModel.IS_DYNAMIC_SCOPE));
assertEquals("", scopeRep.getAttributes().get(ClientScopeModel.DYNAMIC_SCOPE_REGEXP)); assertThat(scopeRep.getAttributes().get(ClientScopeModel.DYNAMIC_SCOPE_REGEXP), anyOf(nullValue(), equalTo("")));
} }
@Test @Test
@ -766,7 +769,7 @@ public class ClientScopeTest extends AbstractClientTest {
clientScopes().get(scopeDefId).update(scopeRep); clientScopes().get(scopeDefId).update(scopeRep);
Assert.fail("This update should fail"); Assert.fail("This update should fail");
} catch (ClientErrorException ex) { } catch (ClientErrorException ex) {
MatcherAssert.assertThat(ex.getResponse(), Matchers.statusCodeIs(Status.BAD_REQUEST)); assertThat(ex.getResponse(), Matchers.statusCodeIs(Status.BAD_REQUEST));
} }
} }
@ -794,7 +797,7 @@ public class ClientScopeTest extends AbstractClientTest {
clientResource.addDefaultClientScope(optionalClientScopeId); clientResource.addDefaultClientScope(optionalClientScopeId);
Assert.fail("A Dynamic Scope shouldn't not be assigned as a default scope to a client"); Assert.fail("A Dynamic Scope shouldn't not be assigned as a default scope to a client");
} catch (ClientErrorException ex) { } catch (ClientErrorException ex) {
MatcherAssert.assertThat(ex.getResponse(), Matchers.statusCodeIs(Status.BAD_REQUEST)); assertThat(ex.getResponse(), Matchers.statusCodeIs(Status.BAD_REQUEST));
} }
} }