/** * 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.apache.aurora.scheduler.storage.testing; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.Collection; import java.util.Map; import java.util.Set; import com.google.common.base.Defaults; import com.google.common.base.Throwables; import com.google.common.collect.ImmutableSet; import com.google.gson.internal.Primitives; import org.apache.thrift.TUnion; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; /** * Utility for validating objects used in storage testing. */ public final class StorageEntityUtil { private StorageEntityUtil() { // Utility class. } private static void assertFullyPopulated(String name, Object object, Set<Field> ignoredFields) { if (object instanceof Collection) { Object[] values = ((Collection<?>) object).toArray(); assertFalse("Collection is empty: " + name, values.length == 0); for (int i = 0; i < values.length; i++) { assertFullyPopulated(name + "[" + i + "]", values[i], ignoredFields); } } else if (object instanceof Map) { Map<?, ?> map = (Map<?, ?>) object; assertFalse("Map is empty: " + name, map.isEmpty()); for (Map.Entry<?, ?> entry : map.entrySet()) { assertFullyPopulated(name + " key", entry.getKey(), ignoredFields); assertFullyPopulated(name + "[" + entry.getKey() + "]", entry.getValue(), ignoredFields); } } else if (object instanceof TUnion) { TUnion<?, ?> union = (TUnion<?, ?>) object; assertFullyPopulated( name + "." + union.getSetField().getFieldName(), union.getFieldValue(), ignoredFields); } else if (!(object instanceof String) && !(object instanceof Enum)) { for (Field field : object.getClass().getDeclaredFields()) { if (!Modifier.isStatic(field.getModifiers())) { validateField(name, object, field, ignoredFields); } } } } private static void validateField( String name, Object object, Field field, Set<Field> ignoredFields) { try { field.setAccessible(true); String fullName = name + "." + field.getName(); Object fieldValue = field.get(object); boolean mustBeSet = !ignoredFields.contains(field); if (mustBeSet) { assertNotNull(fullName + " is null", fieldValue); } if (fieldValue != null) { if (Primitives.isWrapperType(fieldValue.getClass())) { // Special-case the mutable hash code field. if (mustBeSet && !fullName.endsWith("cachedHashCode")) { assertNotEquals( "Primitive value must not be default: " + fullName, Defaults.defaultValue(Primitives.unwrap(fieldValue.getClass())), fieldValue); } } else { assertFullyPopulated(fullName, fieldValue, ignoredFields); } } } catch (IllegalAccessException e) { throw Throwables.propagate(e); } } /** * Ensures that an object tree is fully-populated. This is useful when testing store * implementations to validate that all fields are mapped during a round-trip into and out of * a store implementation. * * @param object Object to ensure is fully populated. * @param <T> Object type. * @return The original {@code object}. */ public static <T> T assertFullyPopulated(T object, Field... ignoredFields) { assertFullyPopulated( object.getClass().getSimpleName(), object, ImmutableSet.copyOf(ignoredFields)); return object; } /** * Convenience method to get a field by name from a class, to pass as an ignored field to * {@link #assertFullyPopulated(Object, Field...)}. * * @param clazz Class to get a field from. * @param field Field name. * @return Field with the given {@code name}. */ public static Field getField(Class<?> clazz, String field) { for (Field f : clazz.getDeclaredFields()) { if (f.getName().equals(field)) { return f; } } throw new IllegalArgumentException("Field not found: " + field); } }