blob: 3c000203dde19d9214e67d2870abb6b408719696 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.brooklyn.test.framework;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import com.google.common.base.Joiner;
import com.google.common.base.Supplier;
import com.google.common.reflect.TypeToken;
import org.apache.brooklyn.api.entity.Entity;
import org.apache.brooklyn.config.ConfigKey;
import org.apache.brooklyn.test.Asserts;
import org.apache.brooklyn.util.core.flags.TypeCoercions;
import org.apache.brooklyn.util.exceptions.CompoundRuntimeException;
import org.apache.brooklyn.util.exceptions.FatalConfigurationRuntimeException;
import org.apache.brooklyn.util.guava.Maybe;
import org.apache.brooklyn.util.text.Strings;
/**
* Utility class to evaluate test-framework assertions
*
* @author m4rkmckenna on 11/11/2015.
*/
public class TestFrameworkAssertions {
public static final String IS_NULL = "isNull";
public static final String NOT_NULL = "notNull";
public static final String IS_EQUAL_TO = "isEqualTo";
public static final String EQUAL_TO = "equalTo";
public static final String EQUALS = "equals";
public static final String MATCHES = "matches";
public static final String CONTAINS = "contains";
public static final String IS_EMPTY = "isEmpty";
public static final String NOT_EMPTY = "notEmpty";
public static final String HAS_TRUTH_VALUE = "hasTruthValue";
public static final String UNKNOWN_CONDITION = "unknown condition";
private TestFrameworkAssertions() {
}
/**
* Get assertions tolerantly from a configuration key.
* This supports either a simple map of assertions, such as
*
<pre>
assertOut:
contains: 2 users
matches: .*[\d]* days.*
</pre>
* or a list of such maps, (which allows you to repeat keys):
<pre>
assertOut:
- contains: 2 users
- contains: 2 days
</pre>
or
private static List<Map<String,Object>> getAssertions(ConfigKey<Object> key) {
}
*/
public static List<Map<String, Object>> getAssertions(Entity entity, ConfigKey<Object> key) {
Object config = entity.getConfig(key);
Maybe<Map<String, Object>> maybeMap = TypeCoercions.tryCoerce(config, new TypeToken<Map<String, Object>>() {});
if (maybeMap.isPresent()) {
return Collections.singletonList(maybeMap.get());
}
Maybe<List<Map<String, Object>>> maybeList = TypeCoercions.tryCoerce(config,
new TypeToken<List<Map<String, Object>>>() {});
if (maybeList.isPresent()) {
return maybeList.get();
}
throw new FatalConfigurationRuntimeException(key.getDescription() + " is not a map or list of maps");
}
public static <T> void checkAssertions(Map<String,?> flags,
Map<String, Object> assertions,
String target,
final Supplier<T> actualSupplier) {
AssertionSupport support = new AssertionSupport();
checkAssertions(support, flags, assertions, target, actualSupplier);
support.validate();
}
public static <T> void checkAssertions(Map<String,?> flags,
List<Map<String, Object>> assertions,
String target,
final Supplier<T> actualSupplier) {
AssertionSupport support = new AssertionSupport();
for (Map<String, Object> assertionMap : assertions) {
checkAssertions(support, flags, assertionMap, target, actualSupplier);
}
support.validate();
}
public static <T> void checkAssertions(final AssertionSupport support,
Map<String,?> flags,
final List<Map<String, Object>> assertions,
final String target,
final Supplier<T> actualSupplier) {
for (Map<String, Object> assertionMap : assertions) {
checkAssertions(support, flags, assertionMap, target, actualSupplier);
}
}
public static <T> void checkAssertions(final AssertionSupport support,
Map<String,?> flags,
final Map<String, Object> assertions,
final String target,
final Supplier<T> actualSupplier) {
if (null == assertions) {
return;
}
try {
Asserts.succeedsEventually(flags, new Runnable() {
@Override
public void run() {
T actual = actualSupplier.get();
checkActualAgainstAssertions(assertions, target, actual);
}
});
} catch (Throwable t) {
support.fail(t);
}
}
private static <T> void checkActualAgainstAssertions(Map<String, Object> assertions,
String target, T actual) {
for (Map.Entry<String, Object> assertion : assertions.entrySet()) {
String condition = assertion.getKey().toString();
Object expected = assertion.getValue();
switch (condition) {
case IS_EQUAL_TO :
case EQUAL_TO :
case EQUALS :
if (null == actual || !actual.equals(expected)) {
failAssertion(target, EQUALS, expected);
}
break;
case IS_NULL :
if (isTrue(expected) != (null == actual)) {
failAssertion(target, IS_NULL, expected);
}
break;
case NOT_NULL :
if (isTrue(expected) != (null != actual)) {
failAssertion(target, NOT_NULL, expected);
}
break;
case CONTAINS :
if (null == actual || !actual.toString().contains(expected.toString())) {
failAssertion(target, CONTAINS, expected);
}
break;
case IS_EMPTY :
if (isTrue(expected) != (null == actual || Strings.isEmpty(actual.toString()))) {
failAssertion(target, IS_EMPTY, expected);
}
break;
case NOT_EMPTY :
if (isTrue(expected) != ((null != actual && Strings.isNonEmpty(actual.toString())))) {
failAssertion(target, NOT_EMPTY, expected);
}
break;
case MATCHES :
if (null == actual || !actual.toString().matches(expected.toString())) {
failAssertion(target, MATCHES, expected);
}
break;
case HAS_TRUTH_VALUE :
if (isTrue(expected) != isTrue(actual)) {
failAssertion(target, HAS_TRUTH_VALUE, expected);
}
break;
default:
failAssertion(target, UNKNOWN_CONDITION, condition);
}
}
}
static void failAssertion(String target, String assertion, Object expected) {
throw new AssertionError(Joiner.on(' ').join(
null != target ? target : "null",
null != assertion ? assertion : "null",
null != expected ? expected : "null"));
}
private static boolean isTrue(Object object) {
return null != object && Boolean.valueOf(object.toString());
}
/**
* A convenience to collect multiple assertion failures.
*/
public static class AssertionSupport {
private List<AssertionError> failures = new ArrayList<>();
public void fail(String target, String assertion, Object expected) {
failures.add(new AssertionError(Joiner.on(' ').join(
null != target ? target : "null",
null != assertion ? assertion : "null",
null != expected ? expected : "null")));
}
public void fail(Throwable throwable) {
failures.add(new AssertionError(throwable.getMessage(), throwable));
}
/**
* @throws AssertionError if any failures were collected.
*/
public void validate() {
if (0 < failures.size()) {
if (1 == failures.size()) {
throw failures.get(0);
}
StringBuilder builder = new StringBuilder();
for (AssertionError assertionError : failures) {
builder.append(assertionError.getMessage()).append("\n");
}
throw new AssertionError("Assertions failed:\n" + builder, new CompoundRuntimeException("Assertions", failures));
}
}
}
}