diff --git a/.gitignore b/.gitignore index bbe265e1..25d57609 100755 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ target +.idea/ *.iws *.ipr *.iml diff --git a/awaitility-groovy/pom.xml b/awaitility-groovy/pom.xml index 0a75dc2b..da7547a3 100755 --- a/awaitility-groovy/pom.xml +++ b/awaitility-groovy/pom.xml @@ -75,15 +75,6 @@ - - org.apache.maven.plugins - maven-compiler-plugin - 2.5.1 - - 1.5 - 1.5 - - diff --git a/awaitility-java8/pom.xml b/awaitility-java8/pom.xml new file mode 100644 index 00000000..4a93fa8f --- /dev/null +++ b/awaitility-java8/pom.xml @@ -0,0 +1,64 @@ + + + 4.0.0 + + awaitility-parent + com.jayway.awaitility + 1.5.1-SNAPSHOT + + awaitility-java8 + Awaitility support for Java 8 + Simplifies Awaitility usage with Java 8 + jar + + + + + maven-compiler-plugin + + 1.8 + 1.8 + + + + maven-install-plugin + 2.5.1 + + + true + + + + + + + + com.jayway.awaitility + awaitility + ${project.version} + test + + + com.jayway.awaitility + awaitility + ${project.version} + test-jar + test + + + org.assertj + assertj-core + 1.6.0 + test + + + junit + junit + 4.10 + test + + + + diff --git a/awaitility-java8/src/main/java/.gitkeep b/awaitility-java8/src/main/java/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/awaitility-java8/src/test/java/com/jayway/awaitility/AwaitilityJava8Test.java b/awaitility-java8/src/test/java/com/jayway/awaitility/AwaitilityJava8Test.java new file mode 100644 index 00000000..b1aac3f8 --- /dev/null +++ b/awaitility-java8/src/test/java/com/jayway/awaitility/AwaitilityJava8Test.java @@ -0,0 +1,82 @@ +package com.jayway.awaitility; + +import com.jayway.awaitility.classes.Asynch; +import com.jayway.awaitility.classes.FakeRepository; +import com.jayway.awaitility.classes.FakeRepositoryImpl; +import com.jayway.awaitility.core.ConditionTimeoutException; +import org.assertj.core.api.Assertions; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import static com.jayway.awaitility.Awaitility.await; +import static com.jayway.awaitility.Awaitility.with; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static org.hamcrest.Matchers.endsWith; +import static org.hamcrest.Matchers.startsWith; +import static org.junit.Assert.assertEquals; + +/** + * Tests for await().until(Runnable) using AssertionCondition. + * + * @author Marcin Zajączkowski, 2014-03-28 + */ +public class AwaitilityJava8Test { + + private FakeRepository fakeRepository; + + @Rule + public ExpectedException exception = ExpectedException.none(); + + @Before + public void setup() { + fakeRepository = new FakeRepositoryImpl(); + Awaitility.reset(); + } + + @Test(timeout = 2000) + public void awaitAssertJAssertionAsLambda() { + new Asynch(fakeRepository).perform(); + await().untilPass(() -> Assertions.assertThat(fakeRepository.getValue()).isEqualTo(1)); + } + + @SuppressWarnings("Convert2Lambda") + @Test(timeout = 2000) + public void awaitAssertJAssertionAsAnonymousClass() { + new Asynch(fakeRepository).perform(); + await().untilPass(new Runnable() { + @Override + public void run() { + Assertions.assertThat(fakeRepository.getValue()).isEqualTo(1); + } + }); + } + + @Test(timeout = 2000) + public void awaitAssertJAssertionDisplaysOriginalErrorMessageAndTimeoutWhenConditionTimeoutExceptionOccurs() { + exception.expect(ConditionTimeoutException.class); + exception.expectMessage(startsWith(AwaitilityJava8Test.class.getName())); + exception.expectMessage(endsWith("expected:<[1]> but was:<[0]> within 120 milliseconds.")); + + new Asynch(fakeRepository).perform(); + with().pollInterval(10, MILLISECONDS).then().await().atMost(120, MILLISECONDS).untilPass( + () -> Assertions.assertThat(fakeRepository.getValue()).isEqualTo(1)); + } + + @Test(timeout = 2000) + public void awaitJUnitAssertionAsLambda() { + new Asynch(fakeRepository).perform(); + await().untilPass(() -> assertEquals(1, fakeRepository.getValue())); + } + + @Test(timeout = 2000) + public void awaitJUnitAssertionDisplaysOriginalErrorMessageAndTimeoutWhenConditionTimeoutExceptionOccurs() { + exception.expect(ConditionTimeoutException.class); + exception.expectMessage(startsWith(AwaitilityJava8Test.class.getName())); + exception.expectMessage(endsWith("expected:<1> but was:<0> within 120 milliseconds.")); + + with().pollInterval(10, MILLISECONDS).then().await().atMost(120, MILLISECONDS).untilPass( + () -> assertEquals(1, fakeRepository.getValue())); + } +} diff --git a/awaitility-scala/pom.xml b/awaitility-scala/pom.xml index 98854530..fa8d1d12 100755 --- a/awaitility-scala/pom.xml +++ b/awaitility-scala/pom.xml @@ -26,7 +26,7 @@ com.jayway.awaitility awaitility - ${version} + ${project.version} @@ -37,6 +37,7 @@ org.scala-tools maven-scala-plugin + 2.15.2 @@ -55,6 +56,7 @@ org.apache.maven.plugins maven-eclipse-plugin + 2.9 true diff --git a/awaitility/pom.xml b/awaitility/pom.xml index 6e3ebf74..d4644a91 100755 --- a/awaitility/pom.xml +++ b/awaitility/pom.xml @@ -5,7 +5,6 @@ awaitility-parent 1.5.1-SNAPSHOT - com.jayway.awaitility awaitility jar http://github.com/jayway/awaitility @@ -16,14 +15,16 @@ - - org.apache.maven.plugins - maven-compiler-plugin - - 1.5 - 1.5 - - + + maven-jar-plugin + + + + test-jar + + + + diff --git a/awaitility/src/main/java/com/jayway/awaitility/core/AssertionCondition.java b/awaitility/src/main/java/com/jayway/awaitility/core/AssertionCondition.java new file mode 100644 index 00000000..536aed90 --- /dev/null +++ b/awaitility/src/main/java/com/jayway/awaitility/core/AssertionCondition.java @@ -0,0 +1,60 @@ +/* + * Copyright 2014 the original author or authors. + * + * 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 com.jayway.awaitility.core; + +import java.util.concurrent.Callable; + +/** + * Condition implementation which takes an executable assertion which should throw {@link AssertionError} on assertion failure. + * + * @since 1.6.0 + * + * @author Marcin Zajączkowski, 2014-03-28 + */ +public class AssertionCondition implements Condition { + + private final ConditionAwaiter conditionAwaiter; + + private String lastExceptionMessage; + + public AssertionCondition(final Runnable supplier, ConditionSettings settings) { + if (supplier == null) { + throw new IllegalArgumentException("You must specify a supplier (was null)."); + } + Callable callable = new Callable() { + public Boolean call() throws Exception { + try { + supplier.run(); + return true; + } catch (AssertionError e) { + lastExceptionMessage = e.getMessage(); + return false; + } + } + }; + conditionAwaiter = new ConditionAwaiter(callable, settings) { + @Override + protected String getTimeoutMessage() { + return supplier.getClass().getName() + " " + lastExceptionMessage; + } + }; + } + + public Void await() { + conditionAwaiter.await(); + return null; + } +} diff --git a/awaitility/src/main/java/com/jayway/awaitility/core/ConditionFactory.java b/awaitility/src/main/java/com/jayway/awaitility/core/ConditionFactory.java index db365a66..6ac2a429 100755 --- a/awaitility/src/main/java/com/jayway/awaitility/core/ConditionFactory.java +++ b/awaitility/src/main/java/com/jayway/awaitility/core/ConditionFactory.java @@ -377,6 +377,44 @@ public T until(final Callable supplier, final Matcher matcher) return until(new CallableHamcrestCondition(supplier, matcher, generateConditionSettings())); } + /** + * Await until a {@link Runnable} supplier execution passes (ends without throwing an exception). E.g. with Java 8: + *

+ *
+     * await().untilPass(() -> Assertions.assertThat(personRepository.size()).isEqualTo(6));
+     * 
+ * or + *
+     * await().untilPass(() -> assertEquals(6, personRepository.size()));
+     * 
+ * + * This method is intended to benefit from lambda expressions introduced in Java 8. It allows to use standard AssertJ/FEST Assert assertions + * (by the way also standard JUnit/TestNG assertions) to test asynchronous calls and systems. + * + * {@link AssertionError} instances thrown by the supplier are treated as an assertion failure and proper error message is propagated on timeout. + * Other exceptions are rethrown immediately as an execution errors. + * + * Why technically it is completely valid to use plain Runnable class in Java 7 code, the resulting expression is very verbose and can decrease + * the readability of the test case, e.g. + *

+ *
+     * await().untilPass(new Runnable() {
+     *     @Override
+     *     public void run() {
+     *         Assertions.assertThat(personRepository.size()).isEqualTo(6);
+     *     }
+     * });
+     * 
+ * + * @param supplier the supplier that is responsible for executing the assertion and throwing AssertionError on failure. + * @throws ConditionTimeoutException If condition was not fulfilled within the given time period. + * + * @since 1.6.0 + */ + public void untilPass(final Runnable supplier) { + until(new AssertionCondition(supplier, generateConditionSettings())); + } + /** * Await until a Atomic variable has a value matching the specified * {@link Matcher}. E.g. diff --git a/pom.xml b/pom.xml index 71cb01e9..dfbe6c5a 100755 --- a/pom.xml +++ b/pom.xml @@ -59,6 +59,7 @@ maven-release-plugin + 2.5 true false @@ -70,7 +71,26 @@ forked-path + + maven-compiler-plugin + + + + + maven-compiler-plugin + 3.1 + + 1.5 + 1.5 + + + + maven-jar-plugin + 2.4 + + + @@ -80,6 +100,7 @@ maven-gpg-plugin + 1.5 false @@ -97,12 +118,14 @@ true maven-deploy-plugin + 2.8.1 true maven-source-plugin + 2.2.1 attach-sources @@ -148,5 +171,6 @@ awaitility awaitility-scala awaitility-groovy + awaitility-java8