| /* |
| * 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; |
| |
| import java.lang.reflect.Array; |
| import java.util.ArrayDeque; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Deque; |
| import java.util.Enumeration; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.concurrent.Callable; |
| import java.util.concurrent.ExecutionException; |
| import java.util.concurrent.TimeoutException; |
| import java.util.concurrent.atomic.AtomicReference; |
| import java.util.function.Predicate; |
| |
| import com.google.common.annotations.Beta; |
| import com.google.common.base.Predicates; |
| import com.google.common.base.Supplier; |
| import com.google.common.base.Suppliers; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableMap; |
| import com.google.common.collect.Iterables; |
| import com.google.common.collect.Lists; |
| import com.google.common.collect.Sets; |
| import groovy.lang.Closure; |
| import org.apache.brooklyn.util.collections.MutableList; |
| import org.apache.brooklyn.util.collections.MutableSet; |
| import org.apache.brooklyn.util.exceptions.CompoundRuntimeException; |
| import org.apache.brooklyn.util.exceptions.Exceptions; |
| import org.apache.brooklyn.util.guava.Maybe; |
| import org.apache.brooklyn.util.javalang.JavaClassNames; |
| import org.apache.brooklyn.util.repeat.Repeater; |
| import org.apache.brooklyn.util.text.ByteSizeStrings; |
| import org.apache.brooklyn.util.text.StringPredicates; |
| import org.apache.brooklyn.util.text.Strings; |
| import org.apache.brooklyn.util.time.CountdownTimer; |
| import org.apache.brooklyn.util.time.Duration; |
| import org.apache.brooklyn.util.time.Time; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| /** |
| * TODO should move this to new package brooklyn.util.assertions |
| * and TODO should add a repeating() method which returns an AssertingRepeater extending Repeater |
| * and: |
| * <ul> |
| * <li> adds support for requireAllIterationsTrue |
| * <li> convenience run methods equivalent to succeedsEventually and succeedsContinually |
| * </ul> |
| * <p> |
| * NOTE Selected routines in this class are originally copied from <a href="http://testng.org">TestNG</a>, to allow us to make assertions without having to |
| * introduce a runtime dependency on TestNG. |
| * </p> |
| */ |
| @Beta |
| public class Asserts { |
| |
| // Used in annotations so needs to be a constant - can't be initialized similarly to DEFAULT_LONG_TIMEOUT |
| // TODO Can we force this by default on all unit tests, beforeMethod, afterMethod methods? |
| public static final long THIRTY_SECONDS_TIMEOUT_MS = 30000; |
| |
| /** |
| * Timeout for use when something should happen. This is the *default timeout* that should |
| * be used by tests (unless that test is asserting performance). |
| * |
| * We willingly accept the hit of slow failing tests, in exchange for removing the |
| * false-negative failures that have historically littered our jenkins builds |
| * (which are presumably sometimes run on over-contended or low-spec machines). |
| * |
| * If the long timeout is irritates during dev (e.g. when doing TDD, where failing tests are |
| * an important step), then one can change this value locally or set using something like |
| * {@code -Dbrooklyn.test.defaultTimeout=1s}. |
| */ |
| public static final Duration DEFAULT_LONG_TIMEOUT; |
| |
| static { |
| String defaultTimeout = System.getProperty("brooklyn.test.defaultTimeout"); |
| if (defaultTimeout == null){ |
| DEFAULT_LONG_TIMEOUT = Duration.millis(THIRTY_SECONDS_TIMEOUT_MS); |
| } else { |
| DEFAULT_LONG_TIMEOUT = Duration.of(defaultTimeout); |
| } |
| } |
| |
| /** |
| * Timeout for use when waiting for other threads to (normally) finish. |
| * <p> |
| * Long enough for parallel execution to (normally!) catch up, even on overloaded mediocre |
| * test boxes most of the time, but short enough not to irritate too much when waiting |
| * this long. |
| * |
| * Never use this for asserting that a condition is satisfied within a given length of time. |
| * Instead use {@link #DEFAULT_LONG_TIMEOUT} to avoid the false-negatives that have |
| * historically littered our jenkins builds. |
| * |
| * Use this constant for asserting that something does *not* happen. If it was going to happen, |
| * then it's reasonable to expect it would normally have happened within this time. For |
| * example, if we are asserting that no more events are received after unsubscribing, then |
| * this would be an appropriate timeout to use (perhaps by using |
| * {@link #succeedsContinually(Runnable)}, which defaults to this timeout). |
| */ |
| public static final Duration DEFAULT_SHORT_TIMEOUT = Duration.ONE_SECOND; |
| |
| private static final Duration DEFAULT_SHORT_PERIOD = Repeater.DEFAULT_REAL_QUICK_PERIOD; |
| |
| private static final Logger log = LoggerFactory.getLogger(Asserts.class); |
| |
| private Asserts() {} |
| |
| private static final Character OPENING_CHARACTER = '['; |
| private static final Character CLOSING_CHARACTER = ']'; |
| |
| private static final String ASSERT_LEFT = "expected " + OPENING_CHARACTER; |
| private static final String ASSERT_MIDDLE = CLOSING_CHARACTER + " but found " + OPENING_CHARACTER; |
| private static final String ASSERT_RIGHT = Character.toString(CLOSING_CHARACTER); |
| |
| static String format(Object actual, Object expected, String message) { |
| String formatted = ""; |
| if (null != message) { |
| formatted = message + " "; |
| } |
| |
| return formatted + ASSERT_LEFT + expected + ASSERT_MIDDLE + actual + ASSERT_RIGHT; |
| } |
| |
| static private void failNotEquals(Object actual , Object expected, String message ) { |
| fail(format(actual, expected, message)); |
| } |
| |
| /** |
| * Assert that an object reference is null. |
| * |
| * @param object The object reference. |
| * |
| * @throws AssertionError if the assertion fails. |
| */ |
| static public void assertNull(final Object object) { |
| assertNull(object, null); |
| } |
| |
| /** |
| * Assert that an object reference is not null. |
| * |
| * @param object The object reference. |
| * |
| * @throws AssertionError if the assertion fails. |
| */ |
| static public void assertNotNull(final Object object) { |
| assertNotNull(object, null); |
| } |
| |
| /** |
| * Assert that an object reference is null. |
| * |
| * @param object The object reference. |
| * @param message The assertion error message. |
| * |
| * @throws AssertionError if the assertion fails. |
| */ |
| static public void assertNull(final Object object, final String message) { |
| if (null != object) { |
| throw new AssertionError(message == null ? "object reference is not null" : message); |
| } |
| } |
| |
| /** |
| * Assert that an object reference is not null. |
| * |
| * @param object The object reference. |
| * @param message The assertion error message. |
| * |
| * @throws AssertionError if the assertion fails. |
| */ |
| static public <T> T assertNotNull(final T object, final String message) { |
| if (null == object) { |
| throw new AssertionError(message == null ? "object reference is null" : message); |
| } |
| return object; |
| } |
| |
| /** |
| * Asserts that two collections contain the same elements in the same order. If they do not, |
| * an AssertionError is thrown. |
| * |
| * @param actual the actual value |
| * @param expected the expected value |
| */ |
| static public void assertEquals(Collection<?> actual, Collection<?> expected) { |
| assertEquals(actual, expected, null); |
| } |
| |
| /** |
| * Asserts that two collections contain the same elements in the same order. If they do not, |
| * an AssertionError, with the given message, is thrown. |
| * @param actual the actual value |
| * @param expected the expected value |
| * @param message the assertion error message |
| */ |
| static public void assertEquals(Collection<?> actual, Collection<?> expected, String message) { |
| if(actual == expected) { |
| return; |
| } |
| |
| if (actual == null || expected == null) { |
| if (message != null) { |
| fail(message); |
| } else { |
| fail("Collections not equal: expected: " + expected + " and actual: " + actual); |
| } |
| } |
| |
| assertEquals(actual.size(), expected.size(), message + ": lists don't have the same size"); |
| |
| Iterator<?> actIt = actual.iterator(); |
| Iterator<?> expIt = expected.iterator(); |
| int i = -1; |
| while(actIt.hasNext() && expIt.hasNext()) { |
| i++; |
| Object e = expIt.next(); |
| Object a = actIt.next(); |
| String explanation = "Lists differ at element [" + i + "]: " + e + " != " + a; |
| String errorMessage = message == null ? explanation : message + ": " + explanation; |
| |
| assertEquals(a, e, errorMessage); |
| } |
| } |
| |
| /** Asserts that two iterators return the same elements in the same order. If they do not, |
| * an AssertionError is thrown. |
| * Please note that this assert iterates over the elements and modifies the state of the iterators. |
| * @param actual the actual value |
| * @param expected the expected value |
| */ |
| static public void assertEquals(Iterator<?> actual, Iterator<?> expected) { |
| assertEquals(actual, expected, null); |
| } |
| |
| /** Asserts that two iterators return the same elements in the same order. If they do not, |
| * an AssertionError, with the given message, is thrown. |
| * Please note that this assert iterates over the elements and modifies the state of the iterators. |
| * @param actual the actual value |
| * @param expected the expected value |
| * @param message the assertion error message |
| */ |
| static public void assertEquals(Iterator<?> actual, Iterator<?> expected, String message) { |
| if(actual == expected) { |
| return; |
| } |
| |
| if(actual == null || expected == null) { |
| if(message != null) { |
| fail(message); |
| } else { |
| fail("Iterators not equal: expected: " + expected + " and actual: " + actual); |
| } |
| } |
| |
| int i = -1; |
| while(actual.hasNext() && expected.hasNext()) { |
| |
| i++; |
| Object e = expected.next(); |
| Object a = actual.next(); |
| String explanation = "Iterators differ at element [" + i + "]: " + e + " != " + a; |
| String errorMessage = message == null ? explanation : message + ": " + explanation; |
| |
| assertEquals(a, e, errorMessage); |
| |
| } |
| |
| if(actual.hasNext()) { |
| |
| String explanation = "Actual iterator returned more elements than the expected iterator."; |
| String errorMessage = message == null ? explanation : message + ": " + explanation; |
| fail(errorMessage); |
| |
| } else if(expected.hasNext()) { |
| |
| String explanation = "Expected iterator returned more elements than the actual iterator."; |
| String errorMessage = message == null ? explanation : message + ": " + explanation; |
| fail(errorMessage); |
| |
| } |
| |
| } |
| |
| /** Asserts that two iterables return iterators with the same elements in the same order. If they do not, |
| * an AssertionError is thrown. |
| * @param actual the actual value |
| * @param expected the expected value |
| */ |
| static public void assertEquals(Iterable<?> actual, Iterable<?> expected) { |
| assertEquals(actual, expected, null); |
| } |
| |
| /** Asserts that two iterables return iterators with the same elements in the same order. If they do not, |
| * an AssertionError, with the given message, is thrown. |
| * @param actual the actual value |
| * @param expected the expected value |
| * @param message the assertion error message |
| */ |
| static public void assertEquals(Iterable<?> actual, Iterable<?> expected, String message) { |
| if(actual == expected) { |
| return; |
| } |
| |
| if(actual == null || expected == null) { |
| if(message != null) { |
| fail(message); |
| } else { |
| fail("Iterables not equal: expected: " + expected + " and actual: " + actual); |
| } |
| } |
| |
| Iterator<?> actIt = actual.iterator(); |
| Iterator<?> expIt = expected.iterator(); |
| |
| assertEquals(actIt, expIt, message); |
| } |
| |
| |
| |
| /** |
| * Asserts that two sets are equal. |
| */ |
| static public void assertEquals(Set<?> actual, Set<?> expected) { |
| assertEquals(actual, expected, null); |
| } |
| |
| /** |
| * Assert set equals |
| */ |
| static public void assertEquals(Set<?> actual, Set<?> expected, String message) { |
| if (actual == expected) { |
| return; |
| } |
| |
| if (actual == null || expected == null) { |
| // Keep the back compatible |
| if (message == null) { |
| fail("Sets not equal: expected: " + expected + " and actual: " + actual); |
| } else { |
| failNotEquals(actual, expected, message); |
| } |
| } |
| |
| if (!actual.equals(expected)) { |
| if (message == null) { |
| fail("Sets differ: expected " + expected + " but got " + actual); |
| } else { |
| failNotEquals(actual, expected, message); |
| } |
| } |
| } |
| |
| /** |
| * Asserts that two maps are equal. |
| */ |
| static public void assertEquals(Map<?, ?> actual, Map<?, ?> expected) { |
| if (actual == expected) { |
| return; |
| } |
| |
| if (actual == null || expected == null) { |
| fail("Maps not equal: expected: " + expected + " and actual: " + actual); |
| } |
| |
| if (actual.size() != expected.size()) { |
| fail("Maps do not have the same size:" + actual.size() + " != " + expected.size()); |
| } |
| |
| Set<?> entrySet = actual.entrySet(); |
| for (Iterator<?> iterator = entrySet.iterator(); iterator.hasNext();) { |
| Map.Entry<?, ?> entry = (Map.Entry<?, ?>) iterator.next(); |
| Object key = entry.getKey(); |
| Object value = entry.getValue(); |
| Object expectedValue = expected.get(key); |
| assertEquals(value, expectedValue, "Maps do not match for key:" + key + " actual:" + value |
| + " expected:" + expectedValue); |
| } |
| |
| } |
| |
| |
| /** |
| * Asserts that two arrays contain the same elements in the same order. If they do not, |
| * an AssertionError, with the given message, is thrown. |
| * @param actual the actual value |
| * @param expected the expected value |
| * @param message the assertion error message |
| */ |
| static public void assertEquals(Object[] actual, Object[] expected, String message) { |
| if(actual == expected) { |
| return; |
| } |
| |
| if ((actual == null && expected != null) || (actual != null && expected == null)) { |
| if (message != null) { |
| fail(message); |
| } else { |
| fail("Arrays not equal: " + Arrays.toString(expected) + " and " + Arrays.toString(actual)); |
| } |
| } |
| assertEquals(Arrays.asList(actual), Arrays.asList(expected), message); |
| } |
| |
| /** |
| * Asserts that two arrays contain the same elements in the same order. If they do not, |
| * an AssertionError is thrown. |
| * |
| * @param actual the actual value |
| * @param expected the expected value |
| */ |
| static public void assertEquals(Object[] actual, Object[] expected) { |
| assertEquals(actual, expected, null); |
| } |
| |
| /** |
| * Asserts that two objects are equal. |
| * @param actual the actual value |
| * @param expected the expected value |
| * |
| * @throws AssertionError if the values are not equal. |
| */ |
| static public void assertEquals(Object actual, Object expected) { |
| assertEquals(actual, expected, null); |
| } |
| |
| /** |
| * Asserts that two objects are equal. |
| * |
| * @param actual the actual value |
| * @param expected the expected value |
| * @param message the assertion error message |
| * |
| * @throws AssertionError if the values are not equal. |
| */ |
| static public void assertEquals(Object actual, Object expected, String message) { |
| if((expected == null) && (actual == null)) { |
| return; |
| } |
| if(expected != null) { |
| if (expected.getClass().isArray()) { |
| assertArrayEquals(actual, expected, message); |
| return; |
| } else if (expected.equals(actual)) { |
| return; |
| } |
| } |
| failNotEquals(actual, expected, message); |
| } |
| |
| |
| /** |
| * Asserts that two objects are equal. It they are not, an AssertionError, |
| * with given message, is thrown. |
| * @param actual the actual value |
| * @param expected the expected value (should be an non-null array value) |
| * @param message the assertion error message |
| */ |
| private static void assertArrayEquals(Object actual, Object expected, String message) { |
| //is called only when expected is an array |
| if (actual.getClass().isArray()) { |
| int expectedLength = Array.getLength(expected); |
| if (expectedLength == Array.getLength(actual)) { |
| for (int i = 0 ; i < expectedLength ; i++) { |
| Object _actual = Array.get(actual, i); |
| Object _expected = Array.get(expected, i); |
| try { |
| assertEquals(_actual, _expected); |
| } catch (AssertionError ae) { |
| failNotEquals(actual, expected, message == null ? "" : message |
| + " (values at index " + i + " are not the same)"); |
| } |
| } |
| //array values matched |
| return; |
| } else { |
| failNotEquals(Array.getLength(actual), expectedLength, message == null ? "" : message |
| + " (Array lengths are not the same)"); |
| } |
| } |
| failNotEquals(actual, expected, message); |
| } |
| |
| |
| /** |
| * Asserts that two Strings are equal. If they are not, |
| * an AssertionError, with the given message, is thrown. |
| * @param actual the actual value |
| * @param expected the expected value |
| * @param message the assertion error message |
| */ |
| static public void assertEquals(String actual, String expected, String message) { |
| assertEquals((Object) actual, (Object) expected, message); |
| } |
| |
| /** |
| * Asserts that two Strings are equal. If they are not, |
| * an AssertionError is thrown. |
| * @param actual the actual value |
| * @param expected the expected value |
| */ |
| static public void assertEquals(String actual, String expected) { |
| assertEquals(actual, expected, null); |
| } |
| |
| /** |
| * Asserts that two doubles are equal within a delta. If they are not, |
| * an AssertionError, with the given message, is thrown. If the expected |
| * value is infinity then the delta value is ignored. |
| * @param actual the actual value |
| * @param expected the expected value |
| * @param delta the absolute tolerable difference between the actual and expected values |
| * @param message the assertion error message |
| */ |
| static public void assertEquals(double actual, double expected, double delta, String message) { |
| // handle infinity specially since subtracting to infinite values gives NaN and the |
| // the following test fails |
| if(Double.isInfinite(expected)) { |
| if(!(expected == actual)) { |
| failNotEquals(new Double(actual), new Double(expected), message); |
| } |
| } |
| else if(!(Math.abs(expected - actual) <= delta)) { // Because comparison with NaN always returns false |
| failNotEquals(new Double(actual), new Double(expected), message); |
| } |
| } |
| |
| /** |
| * Asserts that two doubles are equal within a delta. If they are not, |
| * an AssertionError is thrown. If the expected value is infinity then the |
| * delta value is ignored. |
| * @param actual the actual value |
| * @param expected the expected value |
| * @param delta the absolute tolerable difference between the actual and expected values |
| */ |
| static public void assertEquals(double actual, double expected, double delta) { |
| assertEquals(actual, expected, delta, null); |
| } |
| |
| /** |
| * Asserts that two floats are equal within a delta. If they are not, |
| * an AssertionError, with the given message, is thrown. If the expected |
| * value is infinity then the delta value is ignored. |
| * @param actual the actual value |
| * @param expected the expected value |
| * @param delta the absolute tolerable difference between the actual and expected values |
| * @param message the assertion error message |
| */ |
| static public void assertEquals(float actual, float expected, float delta, String message) { |
| // handle infinity specially since subtracting to infinite values gives NaN and the |
| // the following test fails |
| if(Float.isInfinite(expected)) { |
| if(!(expected == actual)) { |
| failNotEquals(new Float(actual), new Float(expected), message); |
| } |
| } |
| else if(!(Math.abs(expected - actual) <= delta)) { |
| failNotEquals(new Float(actual), new Float(expected), message); |
| } |
| } |
| |
| /** |
| * Asserts that two floats are equal within a delta. If they are not, |
| * an AssertionError is thrown. If the expected |
| * value is infinity then the delta value is ignored. |
| * @param actual the actual value |
| * @param expected the expected value |
| * @param delta the absolute tolerable difference between the actual and expected values |
| */ |
| static public void assertEquals(float actual, float expected, float delta) { |
| assertEquals(actual, expected, delta, null); |
| } |
| |
| /** |
| * Asserts that two longs are equal. If they are not, |
| * an AssertionError, with the given message, is thrown. |
| * @param actual the actual value |
| * @param expected the expected value |
| * @param message the assertion error message |
| */ |
| static public void assertEquals(long actual, long expected, String message) { |
| assertEquals(Long.valueOf(actual), Long.valueOf(expected), message); |
| } |
| |
| /** |
| * Asserts that two longs are equal. If they are not, |
| * an AssertionError is thrown. |
| * @param actual the actual value |
| * @param expected the expected value |
| */ |
| static public void assertEquals(long actual, long expected) { |
| assertEquals(actual, expected, null); |
| } |
| |
| /** |
| * Asserts that two booleans are equal. If they are not, |
| * an AssertionError, with the given message, is thrown. |
| * @param actual the actual value |
| * @param expected the expected value |
| * @param message the assertion error message |
| */ |
| static public void assertEquals(boolean actual, boolean expected, String message) { |
| assertEquals( Boolean.valueOf(actual), Boolean.valueOf(expected), message); |
| } |
| |
| /** |
| * Asserts that two booleans are equal. If they are not, |
| * an AssertionError is thrown. |
| * @param actual the actual value |
| * @param expected the expected value |
| */ |
| static public void assertEquals(boolean actual, boolean expected) { |
| assertEquals(actual, expected, null); |
| } |
| |
| /** |
| * Asserts that two bytes are equal. If they are not, |
| * an AssertionError, with the given message, is thrown. |
| * @param actual the actual value |
| * @param expected the expected value |
| * @param message the assertion error message |
| */ |
| static public void assertEquals(byte actual, byte expected, String message) { |
| assertEquals(Byte.valueOf(actual), Byte.valueOf(expected), message); |
| } |
| |
| /** |
| * Asserts that two bytes are equal. If they are not, |
| * an AssertionError is thrown. |
| * @param actual the actual value |
| * @param expected the expected value |
| */ |
| static public void assertEquals(byte actual, byte expected) { |
| assertEquals(actual, expected, null); |
| } |
| |
| /** |
| * Asserts that two chars are equal. If they are not, |
| * an AssertionFailedError, with the given message, is thrown. |
| * @param actual the actual value |
| * @param expected the expected value |
| * @param message the assertion error message |
| */ |
| static public void assertEquals(char actual, char expected, String message) { |
| assertEquals(Character.valueOf(actual), Character.valueOf(expected), message); |
| } |
| |
| /** |
| * Asserts that two chars are equal. If they are not, |
| * an AssertionError is thrown. |
| * @param actual the actual value |
| * @param expected the expected value |
| */ |
| static public void assertEquals(char actual, char expected) { |
| assertEquals(actual, expected, null); |
| } |
| |
| /** |
| * Asserts that two shorts are equal. If they are not, |
| * an AssertionFailedError, with the given message, is thrown. |
| * @param actual the actual value |
| * @param expected the expected value |
| * @param message the assertion error message |
| */ |
| static public void assertEquals(short actual, short expected, String message) { |
| assertEquals(Short.valueOf(actual), Short.valueOf(expected), message); |
| } |
| |
| /** |
| * Asserts that two shorts are equal. If they are not, |
| * an AssertionError is thrown. |
| * @param actual the actual value |
| * @param expected the expected value |
| */ |
| static public void assertEquals(short actual, short expected) { |
| assertEquals(actual, expected, null); |
| } |
| |
| /** |
| * Asserts that two ints are equal. If they are not, |
| * an AssertionFailedError, with the given message, is thrown. |
| * @param actual the actual value |
| * @param expected the expected value |
| * @param message the assertion error message |
| */ |
| static public void assertEquals(int actual, int expected, String message) { |
| assertEquals(Integer.valueOf(actual), Integer.valueOf(expected), message); |
| } |
| |
| /** |
| * Asserts that two ints are equal. If they are not, |
| * an AssertionError is thrown. |
| * @param actual the actual value |
| * @param expected the expected value |
| */ |
| static public void assertEquals(int actual, int expected) { |
| assertEquals(actual, expected, null); |
| } |
| |
| /** |
| * Asserts that a condition is true. If it isn't, an AssertionError is thrown. |
| * @param condition the condition to evaluate |
| */ |
| public static void assertTrue(boolean condition) { |
| if (!condition) fail(); |
| } |
| |
| /** |
| * Asserts that a condition is true. If it isn't, |
| * an AssertionError, with the given message, is thrown. |
| * @param condition the condition to evaluate |
| * @param message the assertion error message |
| */ |
| public static void assertTrue(boolean condition, String message) { |
| if (!condition) fail(message); |
| } |
| |
| /** |
| * Asserts that a condition is false. If it isn't, |
| * an AssertionError, with the given message, is thrown. |
| * @param condition the condition to evaluate |
| * @param message the assertion error message |
| */ |
| public static void assertFalse(boolean condition, String message) { |
| if (condition) fail(message); |
| } |
| public static void assertFalse(boolean condition) { |
| if (condition) fail(); |
| } |
| |
| /** |
| * Fails a test with the given message. |
| * @param message the assertion error message |
| */ |
| public static AssertionError fail(String message) { |
| throw new AssertionError(message); |
| } |
| public static AssertionError fail(Throwable error) { |
| throw new AssertionError(error); |
| } |
| public static AssertionError fail() { throw new AssertionError(); } |
| |
| public static void assertEqualsIgnoringOrder(Iterable<?> actual, Iterable<?> expected) { |
| assertEqualsIgnoringOrder(actual, expected, false, null); |
| } |
| |
| public static void assertEqualsIgnoringOrder(Iterable<?> actual, Iterable<?> expected, boolean logDuplicates, String errmsg) { |
| Set<?> actualSet = Sets.newLinkedHashSet(actual); |
| Set<?> expectedSet = Sets.newLinkedHashSet(expected); |
| Set<?> extras = Sets.difference(actualSet, expectedSet); |
| Set<?> missing = Sets.difference(expectedSet, actualSet); |
| List<Object> duplicates = Lists.newArrayList(actual); |
| for (Object a : actualSet) { |
| duplicates.remove(a); |
| } |
| String fullErrmsg = "extras="+extras+"; missing="+missing |
| + (logDuplicates ? "; duplicates="+MutableSet.copyOf(duplicates) : "") |
| +"; actualSize="+Iterables.size(actual)+"; expectedSize="+Iterables.size(expected) |
| +"; actual="+actual+"; expected="+expected+"; "+errmsg; |
| assertTrue(extras.isEmpty(), fullErrmsg); |
| assertTrue(missing.isEmpty(), fullErrmsg); |
| assertTrue(Iterables.size(actual) == Iterables.size(expected), fullErrmsg); |
| assertTrue(actualSet.equals(expectedSet), fullErrmsg); // should be covered by extras/missing/size test |
| } |
| |
| // --- new routines |
| |
| /** As {@link #eventually(Supplier, java.util.function.Predicate, Duration, Duration, String)} with defaults. */ |
| public static <T> void eventually(Supplier<? extends T> supplier, java.util.function.Predicate<T> predicate) { |
| eventually(supplier, predicate, null, null, null); |
| } |
| public static <T> void eventually(Supplier<? extends T> supplier, com.google.common.base.Predicate<T> predicate) { |
| eventually(supplier, predicate, null, null, null); |
| } |
| |
| /** As {@link #eventually(Supplier, java.util.function.Predicate, Duration, Duration, String)} with default. */ |
| public static <T> void eventually(Supplier<? extends T> supplier, java.util.function.Predicate<T> predicate, Duration timeout) { |
| eventually(supplier, predicate, timeout, null, null); |
| } |
| public static <T> void eventually(Supplier<? extends T> supplier, com.google.common.base.Predicate<T> predicate, Duration timeout) { |
| eventually(supplier, predicate, timeout, null, null); |
| } |
| |
| /** As {@link #eventually(Supplier, java.util.function.Predicate, Duration, Duration, String)} when no object is going to be notified. */ |
| public static <T> void eventually(Supplier<? extends T> supplier, java.util.function.Predicate<T> predicate, Duration timeout, Duration period, String errMsg) { |
| eventually(supplier, predicate, timeout, period, errMsg, null); |
| } |
| public static <T> void eventually(Supplier<? extends T> supplier, com.google.common.base.Predicate<T> predicate, Duration timeout, Duration period, String errMsg) { |
| eventually(supplier, predicate, timeout, period, errMsg, null); |
| } |
| /** Asserts that eventually the supplier gives a value accepted by the predicate. |
| * Tests periodically and succeeds as soon as the supplier gives an allowed value. |
| * Other arguments can be null. |
| * |
| * @param supplier supplies the value to test, such as {@link Suppliers#ofInstance(Object)} for a constant |
| * @param predicate the {@link java.util.function.Predicate} to apply to each value given by the supplier |
| * @param timeout how long to wait, default {@link #DEFAULT_LONG_TIMEOUT} |
| * @param period how often to check, default quite often so you won't notice but letting the CPU do work |
| * @param errMsg optional error message to display if not satisfied, in addition to the last-tested supplied value and the predicate |
| * @param notifyObject optional object that will be notified of change and should pre-empt the period to redo the check |
| */ |
| public static <T> void eventually(Supplier<? extends T> supplier, java.util.function.Predicate<T> predicate, Duration timeout, Duration period, String errMsg, Object notifyObject) { |
| // TODO use Repeater (there are too many args here) |
| |
| if (timeout==null) timeout = DEFAULT_LONG_TIMEOUT; |
| if (period==null) period = DEFAULT_SHORT_PERIOD; |
| CountdownTimer timeleft = timeout.countdownTimer(); |
| |
| T supplied; |
| int count = 0; |
| do { |
| if (count++ > 0) { |
| if (notifyObject!=null) { |
| synchronized (notifyObject) { |
| try { |
| notifyObject.wait(period.toMilliseconds()); |
| } catch (InterruptedException e) { |
| throw Exceptions.propagate(e); |
| } |
| } |
| } else { |
| Duration.sleep(period); |
| } |
| } |
| supplied = supplier.get(); |
| if (predicate.test(supplied)) return; |
| } while (timeleft.isNotExpired()); |
| |
| fail("Expected: eventually "+predicate+"; got most recently: "+supplied |
| +" (waited "+timeleft.getDurationElapsed()+", checked "+count+")" |
| +(errMsg!=null?"; "+errMsg:"")); |
| } |
| public static <T> void eventually(Supplier<? extends T> supplier, com.google.common.base.Predicate<T> predicate, Duration timeout, Duration period, String errMsg, Object notifyObject) { |
| eventually(supplier, (java.util.function.Predicate<T>) predicate, timeout, period, errMsg, null); |
| } |
| |
| /** As {@link #continually(Supplier, java.util.function.Predicate, Duration, Duration, String)} with defaults. */ |
| public static <T> void continually(Supplier<? extends T> supplier, java.util.function.Predicate<T> predicate) { |
| continually(supplier, predicate, (Duration)null, (Duration)null, (String)null); |
| } |
| public static <T> void continually(Supplier<? extends T> supplier, com.google.common.base.Predicate<T> predicate) { |
| continually(supplier, predicate, (Duration)null, (Duration)null, (String)null); |
| } |
| |
| /** |
| * Asserts that continually the supplier gives a value accepted by the predicate. |
| * Tests periodically and fails if the supplier gives a disallowed value. |
| * Other arguments can be null. |
| * |
| * @param supplier supplies the value to test, such as {@link Suppliers#ofInstance(Object)} for a constant |
| * @param predicate the {@link java.util.function.Predicate} to apply to each value given by the supplier |
| * @param duration how long to test for, default {@link #DEFAULT_SHORT_TIMEOUT} |
| * @param period how often to check, default quite often to minimise chance of missing a flashing violation but letting the CPU do work |
| * @param errMsg an error message to display if not satisfied, in addition to the last-tested supplied value and the predicate |
| */ |
| public static <T> void continually(Supplier<? extends T> supplier, com.google.common.base.Predicate<T> predicate, Duration duration, Duration period, String errMsg) { |
| continually(supplier, (java.util.function.Predicate<T>) predicate, duration, period, errMsg); |
| } |
| public static <T> void continually(Supplier<? extends T> supplier, java.util.function.Predicate<T> predicate, Duration duration, Duration period, String errMsg) { |
| if (duration==null) duration = DEFAULT_SHORT_TIMEOUT; |
| if (period==null) period = DEFAULT_SHORT_PERIOD; |
| |
| CountdownTimer timeleft = duration.countdownTimer(); |
| |
| T supplied; |
| int count = 0; |
| do { |
| if (count > 0) Duration.sleep(period); |
| supplied = supplier.get(); |
| if (!predicate.test(supplied)) { |
| fail("Expected: continually "+predicate+"; got violation: "+supplied |
| // tell timing if it worked the first time and then failed |
| +(count > 0 ? " (after "+timeleft.getDurationElapsed()+", successfully checked "+count+")" : "") |
| +(errMsg!=null?"; "+errMsg:"")); |
| } |
| count++; |
| } while (timeleft.isNotExpired()); |
| } |
| |
| /** |
| * @see #succeedsEventually(Map, Callable) |
| */ |
| public static void succeedsEventually(Runnable r) { |
| succeedsEventually(ImmutableMap.<String,Object>of(), r); |
| } |
| |
| /** |
| * @see #succeedsEventually(Map, Callable) |
| */ |
| public static void succeedsEventually(Map<String,?> flags, Runnable r) { |
| succeedsEventually(flags, toCallable(r)); |
| } |
| |
| /** |
| * @see #succeedsEventually(Map, Callable) |
| */ |
| public static <T> T succeedsEventually(Callable<T> c) { |
| return succeedsEventually(ImmutableMap.<String,Object>of(), c); |
| } |
| |
| // FIXME duplication with TestUtils.BooleanWithMessage |
| public static class BooleanWithMessage { |
| boolean value; String message; |
| public BooleanWithMessage(boolean value, String message) { |
| this.value = value; this.message = message; |
| } |
| public boolean asBoolean() { |
| return value; |
| } |
| @Override |
| public String toString() { |
| return message; |
| } |
| } |
| |
| // TODO flags are ugly; remove this in favour of something strongly typed, |
| // e.g. extending Repeater and taking the extra semantics. |
| // TODO remove the #succeedsEventually in favour of #eventually (and same for continually) |
| // Aled says why? I've found succeedsEventually to be a concise & clear way to write tests. |
| /** |
| * Convenience method for cases where we need to test until something is true. |
| * |
| * The Callable will be invoked periodically until it succesfully concludes. |
| * <p> |
| * The following flags are supported: |
| * <ul> |
| * <li>abortOnError (boolean, default true) |
| * <li>abortOnException - (boolean, default false) |
| * <li>timeout - (a Duration or an integer in millis, defaults to {@link Asserts#DEFAULT_LONG_TIMEOUT}) |
| * <li>period - (a Duration or an integer in millis, for fixed retry time; if not set, defaults to exponentially increasing from 1 to 500ms) |
| * <li>minPeriod - (a Duration or an integer in millis; only used if period not explicitly set; the minimum period when exponentially increasing; defaults to 1ms) |
| * <li>maxPeriod - (a Duration or an integer in millis; only used if period not explicitly set; the maximum period when exponentially increasing; defaults to 500ms) |
| * <li>maxAttempts - (integer, Integer.MAX_VALUE) |
| * </ul> |
| * |
| * The following flags are deprecated: |
| * <ul> |
| * <li>useGroovyTruth - (defaults to false; any result code apart from 'false' will be treated as success including null; ignored for Runnables which aren't Callables) |
| * </ul> |
| * |
| * @param flags, accepts the flags listed above |
| * @param c The callable to invoke |
| */ |
| public static <T> T succeedsEventually(Map<String,?> flags, Callable<T> c) { |
| boolean abortOnException = get(flags, "abortOnException", false); |
| boolean abortOnError = get(flags, "abortOnError", false); |
| boolean useGroovyTruth = get(flags, "useGroovyTruth", false); |
| boolean logException = get(flags, "logException", true); |
| |
| // To speed up tests, default is for the period to start small and increase... |
| Duration duration = toDuration(flags.get("timeout"), DEFAULT_LONG_TIMEOUT); |
| Duration fixedPeriod = toDuration(flags.get("period"), null); |
| Duration minPeriod = (fixedPeriod != null) ? fixedPeriod : toDuration(flags.get("minPeriod"), Duration.millis(1)); |
| Duration maxPeriod = (fixedPeriod != null) ? fixedPeriod : toDuration(flags.get("maxPeriod"), Duration.millis(500)); |
| int maxAttempts = get(flags, "maxAttempts", Integer.MAX_VALUE); |
| int attempt = 0; |
| long startTime = System.currentTimeMillis(); |
| try { |
| Throwable lastException = null; |
| T result = null; |
| long lastAttemptTime = 0; |
| long expireTime = startTime+duration.toMilliseconds(); |
| long sleepTimeBetweenAttempts = minPeriod.toMilliseconds(); |
| |
| while (attempt < maxAttempts && lastAttemptTime < expireTime) { |
| try { |
| attempt++; |
| lastAttemptTime = System.currentTimeMillis(); |
| result = c.call(); |
| if (log.isTraceEnabled()) log.trace("Attempt {} after {} ms: {}", new Object[] {attempt, System.currentTimeMillis() - startTime, result}); |
| if (useGroovyTruth) { |
| if (groovyTruth(result)) return result; |
| } else if (Boolean.FALSE.equals(result)) { |
| if (result instanceof BooleanWithMessage) |
| log.warn("Test returned an instance of BooleanWithMessage but useGroovyTruth is not set! " + |
| "The result of this probably isn't what you intended."); |
| // FIXME surprising behaviour, "false" result here is acceptable |
| return result; |
| } else { |
| return result; |
| } |
| lastException = null; |
| } catch(Throwable e) { |
| Exceptions.propagateIfInterrupt(e); |
| lastException = e; |
| if (log.isTraceEnabled()) log.trace("Attempt {} after {} ms: {}", new Object[] {attempt, System.currentTimeMillis() - startTime, e.getMessage()}); |
| if (abortOnException) throw e; |
| if (abortOnError && e instanceof Error) throw e; |
| } |
| long sleepTime = Math.min(sleepTimeBetweenAttempts, expireTime-System.currentTimeMillis()); |
| if (sleepTime > 0) Thread.sleep(sleepTime); |
| sleepTimeBetweenAttempts = Math.min( |
| // grow by 1.5x; doubling causes longer extra waits than we like in tests |
| sleepTimeBetweenAttempts + Math.max(1, sleepTimeBetweenAttempts/2), |
| maxPeriod.toMilliseconds()); |
| } |
| |
| log.info("succeedsEventually exceeded max attempts or timeout - {} attempts lasting {} ms, for {}", new Object[] {attempt, System.currentTimeMillis()-startTime, c}); |
| if (lastException != null) |
| throw lastException; |
| throw fail("invalid results; last was: "+result); |
| } catch (Throwable t) { |
| Exceptions.propagateIfInterrupt(t); |
| if (logException) log.info("failed succeeds-eventually, "+attempt+" attempts, "+ |
| (System.currentTimeMillis()-startTime)+"ms elapsed "+ |
| "(rethrowing): "+t); |
| throw new AssertionError("failed succeeds-eventually, "+attempt+" attempts, "+ |
| (System.currentTimeMillis()-startTime)+"ms elapsed: "+Exceptions.collapseText(t), t); |
| } |
| } |
| |
| public static <T> void succeedsContinually(Runnable r) { |
| succeedsContinually(ImmutableMap.<String,Object>of(), r); |
| } |
| |
| public static <T> void succeedsContinually(Map<?,?> flags, Runnable r) { |
| succeedsContinually(flags, toCallable(r)); |
| } |
| |
| public static <T> T succeedsContinually(Callable<T> c) { |
| return succeedsContinually(ImmutableMap.<String,Object>of(), c); |
| } |
| |
| // TODO unify with "continually"; see also eventually, some of those options might be useful |
| public static <T> T succeedsContinually(Map<?,?> flags, Callable<T> job) { |
| Duration duration = toDuration(flags.get("timeout"), DEFAULT_SHORT_TIMEOUT); |
| Duration period = toDuration(flags.get("period"), Duration.millis(10)); |
| long periodMs = period.toMilliseconds(); |
| long startTime = System.currentTimeMillis(); |
| long expireTime = startTime+duration.toMilliseconds(); |
| int attempt = 0; |
| |
| boolean first = true; |
| T result = null; |
| while (first || System.currentTimeMillis() <= expireTime) { |
| attempt++; |
| try { |
| result = job.call(); |
| } catch (Exception e) { |
| log.info("succeedsContinually failed - {} attempts lasting {} ms, for {} (rethrowing)", new Object[] {attempt, System.currentTimeMillis()-startTime, job}); |
| throw propagate(e); |
| } |
| if (periodMs > 0) sleep(periodMs); |
| first = false; |
| } |
| return result; |
| } |
| |
| private static Duration toDuration(Object duration, Duration defaultVal) { |
| if (duration == null) |
| return defaultVal; |
| else |
| return Duration.of(duration); |
| } |
| |
| public static void assertFails(Runnable r) { |
| assertFailsWith(toCallable(r), Predicates.alwaysTrue()); |
| } |
| |
| public static void assertFails(Callable<?> c) { |
| assertFailsWith(c, Predicates.alwaysTrue()); |
| } |
| |
| /** |
| * @deprecated since 0.11.0; explicit groovy utilities/support will be deleted. |
| */ |
| @Deprecated |
| public static void assertFailsWith(Callable<?> c, final Closure<Boolean> exceptionChecker) { |
| assertFailsWith(c, (input) -> exceptionChecker.call(input)); |
| } |
| |
| @SafeVarargs |
| public static void assertFailsWith(Runnable c, final Class<? extends Throwable> validException0, final Class<? extends Throwable> ...otherValidExceptions) { |
| final List<Class<?>> validExceptions = ImmutableList.<Class<?>>builder() |
| .add(validException0) |
| .addAll(ImmutableList.copyOf(otherValidExceptions)) |
| .build(); |
| |
| assertFailsWith(c, (e) -> { |
| for (Class<?> validExceptionI: validExceptions) { |
| if (validExceptionI.isInstance(e)) return true; |
| } |
| fail("Test threw exception of unexpected type "+e.getClass()+"; expecting "+validExceptions); |
| return false; |
| }); |
| } |
| |
| public static void assertFailsWith(Runnable r, java.util.function.Predicate<? super Throwable> exceptionChecker) { |
| assertFailsWith(toCallable(r), exceptionChecker, false); |
| } |
| public static void assertFailsWith(Runnable r, com.google.common.base.Predicate<? super Throwable> exceptionChecker) { |
| assertFailsWith(toCallable(r), exceptionChecker, false); |
| } |
| |
| public static void assertFailsWith(Callable<?> c, java.util.function.Predicate<? super Throwable> exceptionChecker) { |
| assertFailsWith(c, exceptionChecker, true); |
| } |
| public static void assertFailsWith(Callable<?> c, com.google.common.base.Predicate<? super Throwable> exceptionChecker) { |
| assertFailsWith(c, exceptionChecker, true); |
| } |
| |
| private static void assertFailsWith(Callable<?> c, java.util.function.Predicate<? super Throwable> exceptionChecker, boolean showResult) { |
| boolean failed = false; |
| Object result = null; |
| try { |
| result = c.call(); |
| } catch (Throwable e) { |
| failed = true; |
| try { |
| if (!exceptionChecker.test(e)) { |
| log.warn("Test threw invalid exception (failing)", e); |
| fail("Test threw invalid exception: " + e); |
| } |
| log.debug("Test for exception successful (" + e + ")"); |
| } catch (Exception e2) { |
| log.warn("Test threw invalid exception (failing)", e); |
| throw Exceptions.propagate(e2); |
| } |
| } |
| if (!failed) fail("Test code should have thrown exception but did not" + |
| (showResult ? "; returned: "+result : "")); |
| } |
| |
| public static void assertReturnsEventually(final Runnable r, Duration timeout) throws InterruptedException, ExecutionException, TimeoutException { |
| final AtomicReference<Throwable> throwable = new AtomicReference<Throwable>(); |
| Runnable wrappedR = new Runnable() { |
| @Override public void run() { |
| try { |
| r.run(); |
| } catch (Throwable t) { |
| throwable.set(t); |
| throw Exceptions.propagate(t); |
| } |
| } |
| }; |
| Thread thread = new Thread(wrappedR, "assertReturnsEventually("+r+")"); |
| try { |
| thread.start(); |
| thread.join(timeout.toMilliseconds()); |
| if (thread.isAlive()) { |
| throw new TimeoutException("Still running: r="+r+"; thread="+Arrays.toString(thread.getStackTrace())); |
| } |
| } catch (InterruptedException e) { |
| throw Exceptions.propagate(e); |
| } finally { |
| thread.interrupt(); |
| } |
| |
| if (throwable.get() != null) { |
| throw new ExecutionException(throwable.get()); |
| } |
| } |
| |
| public static <T> void assertThat(T object, com.google.common.base.Predicate<T> condition) { |
| assertThat(object, condition, null); |
| } |
| public static <T> void assertThat(T object, java.util.function.Predicate<T> condition) { |
| assertThat(object, condition, null); |
| } |
| public static <T> void assertThat(T object, com.google.common.base.Predicate<T> condition, String message) { |
| assertThat(object, (java.util.function.Predicate<T>) condition, message); |
| } |
| public static <T> void assertThat(T object, java.util.function.Predicate<T> condition, String message) { |
| if (condition.test(object)) return; |
| fail(Strings.isBlank(message) ? "Failed "+condition+": "+object : message); |
| } |
| |
| public static void assertStringContains(String input, String phrase1ToContain, String ...optionalOtherPhrasesToContain) { |
| if (input==null) fail("Input is null."); |
| if (phrase1ToContain!=null) { |
| assertThat(input, StringPredicates.containsLiteral(phrase1ToContain)); |
| } |
| for (String otherPhrase: optionalOtherPhrasesToContain) { |
| if (otherPhrase!=null) { |
| assertThat(input, StringPredicates.containsLiteral(otherPhrase)); |
| } |
| } |
| } |
| |
| public static void assertStringDoesNotContain(String input, String phrase1ToNotContain, String ...optionalOtherPhrasesToNotContain) { |
| if (input==null) fail("Input is null."); |
| if (phrase1ToNotContain!=null) { |
| assertThat(input, Predicates.not(StringPredicates.containsLiteral(phrase1ToNotContain))); |
| } |
| for (String otherPhrase: optionalOtherPhrasesToNotContain) { |
| if (otherPhrase!=null) { |
| assertThat(input, Predicates.not(StringPredicates.containsLiteral(otherPhrase))); |
| } |
| } |
| } |
| |
| public static void assertStringContainsAtLeastOne(String input, String possiblePhrase1ToContain, String ...optionalOtherPossiblePhrasesToContain) { |
| if (input==null) fail("Input is null."); |
| List<String> missing = MutableList.of(); |
| if (possiblePhrase1ToContain!=null) { |
| if (input.contains(possiblePhrase1ToContain)) return; |
| missing.add(possiblePhrase1ToContain); |
| } |
| for (String otherPhrase: optionalOtherPossiblePhrasesToContain) { |
| if (otherPhrase!=null) { |
| if (input.contains(otherPhrase)) return; |
| missing.add(otherPhrase); |
| } |
| } |
| fail("Input did not contain any of the expected phrases "+missing+": "+input); |
| } |
| |
| public static void assertStringContainsIgnoreCase(String input, String phrase1ToContain, String ...optionalOtherPhrasesToContain) { |
| if (input==null) fail("Input is null."); |
| if (phrase1ToContain!=null) { |
| assertThat(input, StringPredicates.containsLiteralIgnoreCase(phrase1ToContain)); |
| } |
| for (String otherPhrase: optionalOtherPhrasesToContain) { |
| if (otherPhrase!=null) { |
| assertThat(input, StringPredicates.containsLiteralIgnoreCase(otherPhrase)); |
| } |
| } |
| } |
| |
| public static void assertStringDoesNotContainIgnoreCase(String input, String phrase1ToNotContain, String ...optionalOtherPhrasesToNotContain) { |
| if (input==null) fail("Input is null."); |
| if (phrase1ToNotContain!=null) { |
| assertThat(input, Predicates.not(StringPredicates.containsLiteralIgnoreCase(phrase1ToNotContain))); |
| } |
| for (String otherPhrase: optionalOtherPhrasesToNotContain) { |
| if (otherPhrase!=null) { |
| assertThat(input, Predicates.not(StringPredicates.containsLiteralIgnoreCase(otherPhrase))); |
| } |
| } |
| } |
| |
| public static void assertStringMatchesRegex(String input, String regex1ToMatch, String ...optionalOtherRegexesToMatch) { |
| if (input==null) fail("Input is null."); |
| if (regex1ToMatch!=null) { |
| assertThat(input, StringPredicates.matchesRegex(regex1ToMatch)); |
| } |
| for (String otherRegex: optionalOtherRegexesToMatch) { |
| if (otherRegex!=null) { |
| assertThat(input, StringPredicates.matchesRegex(otherRegex)); |
| } |
| } |
| } |
| |
| /** Subclass of {@link AssertionError} which indicates that code which should have thrown did not, |
| * so that callers can disambiguate expected errors from this one. |
| * See {@link #shouldHaveFailedPreviously()} */ |
| public static class ShouldHaveFailedPreviouslyAssertionError extends AssertionError { |
| private static final long serialVersionUID = 4359541529633617518L; |
| public ShouldHaveFailedPreviouslyAssertionError() { this("Should have failed previously."); } |
| public ShouldHaveFailedPreviouslyAssertionError(String message) { super(message); } |
| } |
| |
| /** Throws a {@link ShouldHaveFailedPreviouslyAssertionError} exception, |
| * to more easily distinguish this failure from other fails. |
| * In particular, use one of the <code>expectedFailure</code> methods |
| * in the surrounding <code>catch</code> block and this error will pass through it. |
| * <p> |
| * This method throws, never returning normally, but declares a return type |
| * so you can pretend to throw the result, |
| * for instance if your calling code otherwise warns about needing to return something. */ |
| public static RuntimeException shouldHaveFailedPreviously() { |
| throw new ShouldHaveFailedPreviouslyAssertionError(); |
| } |
| /** As {@link #shouldHaveFailedPreviously()} but allowing detail, |
| * for example a value which was received when it shouldn't have been. */ |
| public static void shouldHaveFailedPreviously(String message) { |
| throw new ShouldHaveFailedPreviouslyAssertionError(message); |
| } |
| |
| /** Tests that an exception is not {@link ShouldHaveFailedPreviouslyAssertionError}. |
| * See {@link #shouldHaveFailedPreviously()} */ |
| public static void expectedFailure(Throwable e) { |
| if (e instanceof ShouldHaveFailedPreviouslyAssertionError) throw (Error)e; |
| } |
| |
| /** |
| * Tests that an exception is not {@link ShouldHaveFailedPreviouslyAssertionError} |
| * and is either one of the given types, or has a caused-by of one of the given types. |
| * |
| * If you want *just* the instanceof (without checking the caused-by), then just catch |
| * those exception types, treat that as success, and let any other exception be propagated. |
| * |
| * @return If the test is satisfied, this method returns normally. |
| * The caller can decide whether anything more should be done with the exception. |
| * If the test fails, then either it is propagated, |
| * if the {@link Throwable} is a fatal ({@link Exceptions#propagateIfFatal(Throwable)}) other than an {@link AssertionError}, |
| * or more usually the test failure of this method is thrown, |
| * with detail of the original {@link Throwable} logged and included in the caused-by. |
| */ |
| public static void expectedFailureOfType(Throwable e, Class<?> permittedSupertype, Class<?> ...permittedSupertypes) { |
| expectedFailureOfType(null, e, permittedSupertype, permittedSupertypes); |
| } |
| @SuppressWarnings("unchecked") |
| public static void expectedFailureOfType(String message, Throwable e, Class<?> permittedSupertype, Class<?> ...permittedSupertypeExtras) { |
| @SuppressWarnings("rawtypes") |
| List<Class<?>> permittedSupertypes = MutableList.of(permittedSupertype).appendAll((List)Arrays.asList(permittedSupertypeExtras)); |
| if (e instanceof ShouldHaveFailedPreviouslyAssertionError) throw (Error) e; |
| for (Class<?> clazz: permittedSupertypes) { |
| if (Exceptions.getFirstThrowableOfType(e, (Class<? extends Throwable>)clazz) != null) { |
| return; |
| } |
| } |
| rethrowPreferredException(e, |
| new AssertionError((message!=null ? message+": " : "") + "Error "+JavaClassNames.simpleClassName(e)+" is not any of the expected types: " + permittedSupertypes, e)); |
| } |
| |
| /** Tests {@link #expectedFailure(Throwable)} and that the <code>toString</code> |
| * satisfies {@link #assertStringContains(String, String, String...)}. |
| * @return as per {@link #expectedFailureOfType(Throwable, Class, Class...)} */ |
| public static boolean expectedFailureContains(Throwable e, String phrase1ToContain, String ...optionalOtherPhrasesToContain) { |
| if (e instanceof ShouldHaveFailedPreviouslyAssertionError) throw (Error)e; |
| try { |
| assertStringContains(Exceptions.collapseText(e), phrase1ToContain, optionalOtherPhrasesToContain); |
| } catch (AssertionError ee) { |
| rethrowPreferredException(e, ee); |
| } |
| return true; |
| } |
| |
| /** As {@link #expectedFailureContains(Throwable, String, String...)} but case insensitive */ |
| public static boolean expectedFailureContainsIgnoreCase(Throwable e, String phrase1ToContain, String ...optionalOtherPhrasesToContain) { |
| if (e instanceof ShouldHaveFailedPreviouslyAssertionError) throw (Error)e; |
| try { |
| assertStringContainsIgnoreCase(Exceptions.collapseText(e), phrase1ToContain, optionalOtherPhrasesToContain); |
| } catch (AssertionError ee) { |
| rethrowPreferredException(e, ee); |
| } |
| return true; |
| } |
| public static Predicate<Throwable> expectedFailureContains(String phrase1ToContain, String ...optionalOtherPhrasesToContain) { |
| return e -> expectedFailureContains(e, phrase1ToContain, optionalOtherPhrasesToContain); |
| } |
| public static Predicate<Throwable> expectedFailureContainsIgnoreCase(String phrase1ToContain, String ...optionalOtherPhrasesToContain) { |
| return e -> expectedFailureContainsIgnoreCase(e, phrase1ToContain, optionalOtherPhrasesToContain); |
| } |
| |
| /** As {@link #expectedFailureContains(Throwable, String, String...)} but case insensitive */ |
| public static boolean expectedCompoundExceptionContainsIgnoreCase(CompoundRuntimeException e, String phrase1ToContain, String ...optionalOtherPhrasesToContain) { |
| for (Throwable t : e.getAllCauses()) { |
| if (t instanceof ShouldHaveFailedPreviouslyAssertionError) throw (Error)t; |
| try { |
| expectedFailureContainsIgnoreCase(t, phrase1ToContain, optionalOtherPhrasesToContain); |
| return true; |
| } catch (AssertionError ee) {} |
| } |
| throw new CompoundRuntimeException("Expected literals not found: " + phrase1ToContain + ", " + optionalOtherPhrasesToContain, e); |
| } |
| |
| /** Tests {@link #expectedFailure(Throwable)} and that the <code>toString</code> |
| * satisfies {@link #assertStringContains(String, String, String...)}. |
| * @return as per {@link #expectedFailureOfType(Throwable, Class, Class...)} */ |
| public static boolean expectedFailureDoesNotContain(Throwable e, String phrase1ToNotContain, String ...optionalOtherPhrasesToNotContain) { |
| if (e instanceof ShouldHaveFailedPreviouslyAssertionError) throw (Error)e; |
| try { |
| assertStringDoesNotContain(Exceptions.collapseText(e), phrase1ToNotContain, optionalOtherPhrasesToNotContain); |
| } catch (AssertionError ee) { |
| rethrowPreferredException(e, ee); |
| } |
| return true; |
| } |
| public static boolean expectedFailureDoesNotContainIgnoreCase(Throwable e, String phrase1ToNotContain, String ...optionalOtherPhrasesToNotContain) { |
| if (e instanceof ShouldHaveFailedPreviouslyAssertionError) throw (Error)e; |
| try { |
| assertStringDoesNotContainIgnoreCase(Exceptions.collapseText(e), phrase1ToNotContain, optionalOtherPhrasesToNotContain); |
| } catch (AssertionError ee) { |
| rethrowPreferredException(e, ee); |
| } |
| return true; |
| } |
| public static Predicate<Throwable> expectedFailureDoesNotContain( String phrase1ToNotContain, String ...optionalOtherPhrasesToNotContain) { |
| return e -> expectedFailureDoesNotContain(e, phrase1ToNotContain, optionalOtherPhrasesToNotContain); |
| } |
| public static Predicate<Throwable> expectedFailureDoesNotContainIgnoreCase(String phrase1ToNotContain, String ...optionalOtherPhrasesToNotContain) { |
| return e -> expectedFailureDoesNotContainIgnoreCase(e, phrase1ToNotContain, optionalOtherPhrasesToNotContain); |
| } |
| |
| /** Implements the return behavior for {@link #expectedFailureOfType(Throwable, Class, Class...)} and others, |
| * to log interesting earlier errors but to suppress those which are internal or redundant. */ |
| private static void rethrowPreferredException(Throwable earlierPreferredIfFatalElseLogged, Throwable laterPreferredOtherwise) throws AssertionError { |
| if (!(earlierPreferredIfFatalElseLogged instanceof AssertionError)) { |
| Exceptions.propagateIfFatal(earlierPreferredIfFatalElseLogged); |
| } |
| log.warn("Detail of unexpected error: "+earlierPreferredIfFatalElseLogged, earlierPreferredIfFatalElseLogged); |
| throw Exceptions.propagate(laterPreferredOtherwise); |
| } |
| |
| @SuppressWarnings("rawtypes") |
| private static boolean groovyTruth(Object o) { |
| // TODO Doesn't handle matchers (see http://docs.codehaus.org/display/GROOVY/Groovy+Truth) |
| if (o == null) { |
| return false; |
| } else if (o instanceof Boolean) { |
| return (Boolean)o; |
| } else if (o instanceof String) { |
| return !((String)o).isEmpty(); |
| } else if (o instanceof Collection) { |
| return !((Collection)o).isEmpty(); |
| } else if (o instanceof Map) { |
| return !((Map)o).isEmpty(); |
| } else if (o instanceof Iterator) { |
| return ((Iterator)o).hasNext(); |
| } else if (o instanceof Enumeration) { |
| return ((Enumeration)o).hasMoreElements(); |
| } else { |
| return true; |
| } |
| } |
| |
| @SuppressWarnings("unchecked") |
| private static <T> T get(Map<String,?> map, String key, T defaultVal) { |
| Object val = map.get(key); |
| return (T) ((val == null) ? defaultVal : val); |
| } |
| |
| private static Callable<?> toCallable(Runnable r) { |
| return (r instanceof Callable) ? (Callable<?>)r : new RunnableAdapter<Void>(r, null); |
| } |
| |
| /** Same as {@link java.util.concurrent.Executors#callable(Runnable)}, except includes toString() */ |
| static final class RunnableAdapter<T> implements Callable<T> { |
| final Runnable task; |
| final T result; |
| RunnableAdapter(Runnable task, T result) { |
| this.task = task; |
| this.result = result; |
| } |
| @Override |
| public T call() { |
| task.run(); |
| return result; |
| } |
| @Override |
| public String toString() { |
| return "RunnableAdapter("+task+")"; |
| } |
| } |
| |
| private static void sleep(long periodMs) { |
| if (periodMs > 0) { |
| try { |
| Thread.sleep(periodMs); |
| } catch (InterruptedException e) { |
| throw propagate(e); |
| } |
| } |
| } |
| |
| private static RuntimeException propagate(Throwable t) { |
| throw Exceptions.propagate(t); |
| } |
| |
| /** As {@link #eventuallyOnNotify(Object, Supplier, java.util.function.Predicate, Duration)} with default timeout. */ |
| public static <T> void eventuallyOnNotify(Object notifyTarget, Supplier<T> supplier, com.google.common.base.Predicate<T> predicate) { |
| eventuallyOnNotify(notifyTarget, supplier, predicate, null); |
| } |
| public static <T> void eventuallyOnNotify(Object notifyTarget, Supplier<T> supplier, java.util.function.Predicate<T> predicate) { |
| eventuallyOnNotify(notifyTarget, supplier, predicate, null); |
| } |
| |
| /** as {@link #eventually(Supplier, java.util.function.Predicate)} for cases where an object is notified; |
| * more efficient as it waits on the notify target object. |
| * See also the simpler {@link #eventuallyOnNotify(Object, java.util.function.Predicate)} when looking at a collection which is getting notified. |
| * Timeout defaults to {@link #DEFAULT_SHORT_TIMEOUT}. |
| * <p> |
| * This synchronizes on the notify target for the duration of the wait, |
| * including while getting and checking the value, so as not to miss any notification. */ |
| public static <T> void eventuallyOnNotify(Object notifyTarget, Supplier<T> supplier, com.google.common.base.Predicate<T> predicate, Duration timeout) { |
| eventuallyOnNotify(notifyTarget, supplier, (java.util.function.Predicate<T>)predicate, timeout); |
| } |
| public static <T> void eventuallyOnNotify(Object notifyTarget, Supplier<T> supplier, java.util.function.Predicate<T> predicate, Duration timeout) { |
| T supplied = null; |
| if (timeout==null) timeout = DEFAULT_SHORT_TIMEOUT; |
| CountdownTimer remaining = timeout.countdownTimer(); |
| int checks = 0; |
| synchronized (notifyTarget) { |
| do { |
| if (checks>0) { |
| remaining.waitOnForExpiryUnchecked(notifyTarget); |
| } |
| supplied = supplier.get(); |
| if (predicate.test(supplied)) return; |
| checks++; |
| } while (remaining.isNotExpired()); |
| } |
| |
| // should get 2 checks, 1 before and 1 after, if no notifications; if more, tell the user |
| fail("Expected: eventually "+predicate+"; got most recently: "+supplied+ |
| " (waited "+remaining.getDurationElapsed()+ |
| (checks>2 ? "; notification count "+(checks-2) : "")+ |
| ")"); |
| } |
| |
| /** Convenience for {@link #eventuallyOnNotify(Object, Supplier, java.util.function.Predicate, Duration)} |
| * when the notify target and the value under test are the same. */ |
| public static <T> void eventuallyOnNotify(T object, java.util.function.Predicate<T> predicate, Duration timeout) { |
| eventuallyOnNotify(object, Suppliers.ofInstance(object), predicate, timeout); |
| } |
| public static <T> void eventuallyOnNotify(T object, com.google.common.base.Predicate<T> predicate, Duration timeout) { |
| eventuallyOnNotify(object, Suppliers.ofInstance(object), predicate, timeout); |
| } |
| |
| /** As {@link #eventuallyOnNotify(Object, java.util.function.Predicate, Duration)} with the default duration of {@link #eventuallyOnNotify(Object, Supplier, java.util.function.Predicate)}. */ |
| public static <T> void eventuallyOnNotify(T object, java.util.function.Predicate<T> predicate) { |
| eventuallyOnNotify(object, Suppliers.ofInstance(object), predicate, null); |
| } |
| public static <T> void eventuallyOnNotify(T object, com.google.common.base.Predicate<T> predicate) { |
| eventuallyOnNotify(object, Suppliers.ofInstance(object), predicate, null); |
| } |
| |
| public static void assertSize(Iterable<?> list, int expectedSize) { |
| if (list==null) fail("Collection is null"); |
| if (Iterables.size(list)!=expectedSize) fail("Collection has wrong size "+Iterables.size(list)+" (expected "+expectedSize+"): "+list); |
| } |
| |
| public static void assertSize(Map<?,?> map, int expectedSize) { |
| if (map==null) fail("Map is null"); |
| if (Iterables.size(map.keySet())!=expectedSize) fail("Map has wrong size "+map.size()+" (expected "+expectedSize+"): "+map); |
| } |
| |
| /** Ignores duplicates and order */ |
| public static void assertSameUnorderedContents(Iterable<?> i1, Iterable<?> i2) { |
| if (i1==null || i2==null) { |
| if (i1==null && i2==null) { |
| return ; |
| } |
| fail("Collections differ in that one is null: "+i1+" and "+i2); |
| } |
| assertEquals(MutableSet.copyOf(i1), MutableSet.copyOf(i2)); |
| } |
| |
| public static void assertInstanceOf(Object obj, Class<?> type) { |
| assertThat(obj, Predicates.instanceOf(type), "Expected "+type+" but found "+(obj==null ? "null" : obj+" ("+obj.getClass()+")")); |
| } |
| |
| public static <T> T assertPresent(Maybe<T> candidate) { |
| if (candidate.isPresent()) return candidate.get(); |
| throw fail( Maybe.getException(candidate) ); |
| } |
| |
| public static <T> void assertNotPresent(Maybe<T> candidate) { |
| if (candidate.isAbsent()) return; |
| throw fail("Expected absent value; instead got: "+candidate.get()); |
| } |
| |
| public static <T> void assertEntriesSatisfy(Collection<T> list, Collection<java.util.function.Predicate<T>> tests) { |
| Asserts.assertEquals(list.size(), tests.size(), "List of test is different length to list of data to test"); |
| Iterator<T> li = list.iterator(); |
| Iterator<java.util.function.Predicate<T>> ti = tests.iterator(); |
| for (int i=0; i<list.size(); i++) { |
| T l = li.next(); |
| Asserts.assertTrue(ti.next().test(l), "Failed at index "+i+": "+l); |
| } |
| } |
| |
| public static MemoryAssertions startMemoryAssertions(String message) { |
| MemoryAssertions result = new MemoryAssertions(); |
| result.pushUsedMemory(message); |
| return result; |
| } |
| |
| public static class MemoryAssertions { |
| public MemoryAssertions() { |
| } |
| |
| Runnable extraTaskOnNoteMemory; |
| Deque<Long> usedMemoryQueue = new ArrayDeque<>(); |
| |
| public void setExtraTaskOnNoteMemory(Runnable extraTaskOnNoteMemory) { |
| this.extraTaskOnNoteMemory = extraTaskOnNoteMemory; |
| } |
| |
| public long pushUsedMemory(String message) { |
| Time.sleep(Duration.millis(200)); |
| if (extraTaskOnNoteMemory!=null) { |
| extraTaskOnNoteMemory.run(); |
| } |
| System.gc(); System.gc(); |
| Time.sleep(Duration.millis(50)); |
| System.gc(); System.gc(); |
| long mem = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory(); |
| usedMemoryQueue.addLast(mem); |
| log.info("Memory used - "+message+": "+ByteSizeStrings.java().apply(mem)); |
| return mem; |
| } |
| |
| public long popUsedMemory() { |
| return usedMemoryQueue.removeLast(); |
| } |
| |
| public long peekLastUsedMemory() { |
| return usedMemoryQueue.peekLast(); |
| } |
| |
| public void assertUsedMemoryLessThan(String event, long max, boolean push) { |
| assertUsedMemoryLessThan(event, max, push, null); |
| } |
| |
| public void assertUsedMemoryLessThan(String event, long max, boolean push, String extraFailMessage) { |
| long nowUsed = pushUsedMemory(event); |
| if (nowUsed > max) { |
| // aggressively try to force GC |
| Time.sleep(Duration.ONE_SECOND); |
| popUsedMemory(); |
| nowUsed = pushUsedMemory(event+" (extra GC)"); |
| if (nowUsed > max) { |
| fail("Too much memory used - "+ ByteSizeStrings.java().apply(nowUsed)+" > max "+ByteSizeStrings.java().apply(max)+ |
| (extraFailMessage==null ? "" : " "+extraFailMessage)); |
| } |
| } |
| if (!push) popUsedMemory(); |
| } |
| public void assertUsedMemoryMaxDelta(String event, long deltaMegabytes, boolean push) { |
| final long last = peekLastUsedMemory(); |
| assertUsedMemoryLessThan(event, last + deltaMegabytes*1024*1024, push, "(prev was "+ByteSizeStrings.java().apply(last)+", delta limit was "+ByteSizeStrings.java().apply(deltaMegabytes*1024*1024)+")"); |
| } |
| } |
| } |