Return-Path:
X-Original-To: apmail-geode-commits-archive@minotaur.apache.org
Delivered-To: apmail-geode-commits-archive@minotaur.apache.org
Received: from mail.apache.org (hermes.apache.org [140.211.11.3])
by minotaur.apache.org (Postfix) with SMTP id 043391858B
for ;
Thu, 21 Jan 2016 19:09:18 +0000 (UTC)
Received: (qmail 35419 invoked by uid 500); 21 Jan 2016 19:09:17 -0000
Delivered-To: apmail-geode-commits-archive@geode.apache.org
Received: (qmail 35382 invoked by uid 500); 21 Jan 2016 19:09:17 -0000
Mailing-List: contact commits-help@geode.incubator.apache.org; run by ezmlm
Precedence: bulk
List-Help:
List-Unsubscribe:
List-Post:
List-Id:
Reply-To: dev@geode.incubator.apache.org
Delivered-To: mailing list commits@geode.incubator.apache.org
Received: (qmail 35373 invoked by uid 99); 21 Jan 2016 19:09:17 -0000
Received: from Unknown (HELO spamd4-us-west.apache.org) (209.188.14.142)
by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 21 Jan 2016 19:09:17 +0000
Received: from localhost (localhost [127.0.0.1])
by spamd4-us-west.apache.org (ASF Mail Server at spamd4-us-west.apache.org)
with ESMTP id 3BBA8C0E80
for ; Thu, 21 Jan 2016 19:09:17 +0000 (UTC)
X-Virus-Scanned: Debian amavisd-new at spamd4-us-west.apache.org
X-Spam-Flag: NO
X-Spam-Score: 1.227
X-Spam-Level: *
X-Spam-Status: No, score=1.227 tagged_above=-999 required=6.31
tests=[KAM_ASCII_DIVIDERS=0.8, KAM_LAZY_DOMAIN_SECURITY=1,
RCVD_IN_MSPIKE_H3=-0.01, RCVD_IN_MSPIKE_WL=-0.01,
RP_MATCHES_RCVD=-0.554, URIBL_BLOCKED=0.001] autolearn=disabled
Received: from mx1-us-west.apache.org ([10.40.0.8])
by localhost (spamd4-us-west.apache.org [10.40.0.11]) (amavisd-new,
port 10024)
with ESMTP id iLeU-tZjYKfJ for ;
Thu, 21 Jan 2016 19:08:57 +0000 (UTC)
Received: from mail.apache.org (hermes.apache.org [140.211.11.3])
by mx1-us-west.apache.org (ASF Mail Server at mx1-us-west.apache.org) with
SMTP id 2931E20F88
for ;
Thu, 21 Jan 2016 19:08:48 +0000 (UTC)
Received: (qmail 33328 invoked by uid 99); 21 Jan 2016 19:08:47 -0000
Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org)
(140.211.11.23)
by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 21 Jan 2016 19:08:47 +0000
Received: by git1-us-west.apache.org (ASF Mail Server at
git1-us-west.apache.org, from userid 33)
id BDD11E38D3; Thu, 21 Jan 2016 19:08:47 +0000 (UTC)
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
From: klund@apache.org
To: commits@geode.incubator.apache.org
Date: Thu, 21 Jan 2016 19:09:04 -0000
Message-Id: <9142b8f3a50b4216bb48b73f980f89ab@git.apache.org>
In-Reply-To: <4a1a3f20ce0648d6aaed99edeb5f3034@git.apache.org>
References: <4a1a3f20ce0648d6aaed99edeb5f3034@git.apache.org>
X-Mailer: ASF-Git Admin Mailer
Subject: [18/19] incubator-geode git commit: GEODE-772: Add custom annotations
and rules for tests
GEODE-772: Add custom annotations and rules for tests
Project: http://git-wip-us.apache.org/repos/asf/incubator-geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-geode/commit/1be4f932
Tree: http://git-wip-us.apache.org/repos/asf/incubator-geode/tree/1be4f932
Diff: http://git-wip-us.apache.org/repos/asf/incubator-geode/diff/1be4f932
Branch: refs/heads/feature/GEODE-715
Commit: 1be4f932a80f53c0588b49227e7daa518eb389c5
Parents: c0c64de
Author: Kirk Lund
Authored: Wed Jan 20 16:30:20 2016 -0800
Committer: Kirk Lund
Committed: Thu Jan 21 10:48:44 2016 -0800
----------------------------------------------------------------------
.../gemfire/test/junit/ConditionalIgnore.java | 49 +++
.../gemfire/test/junit/IgnoreCondition.java | 32 ++
.../gemfire/test/junit/IgnoreUntil.java | 49 +++
.../com/gemstone/gemfire/test/junit/Repeat.java | 43 +++
.../com/gemstone/gemfire/test/junit/Retry.java | 38 +++
.../test/junit/rules/ConditionalIgnoreRule.java | 123 ++++++++
.../test/junit/rules/ExpectedTimeoutRule.java | 180 +++++++++++
.../test/junit/rules/IgnoreUntilRule.java | 123 ++++++++
.../gemfire/test/junit/rules/RepeatRule.java | 81 +++++
.../gemfire/test/junit/rules/RetryRule.java | 181 +++++++++++
.../rules/SerializableExternalResource.java | 107 +++++++
.../test/junit/rules/SerializableRuleChain.java | 119 ++++++++
.../rules/SerializableTemporaryFolder.java | 70 +++++
.../test/junit/rules/SerializableTestName.java | 54 ++++
.../test/junit/rules/SerializableTestRule.java | 33 ++
.../junit/rules/SerializableTestWatcher.java | 29 ++
.../test/junit/rules/SerializableTimeout.java | 119 ++++++++
.../examples/RepeatingTestCasesExampleTest.java | 94 ++++++
.../rules/examples/RetryRuleExampleTest.java | 43 +++
.../rules/tests/ExpectedTimeoutRuleTest.java | 214 +++++++++++++
.../junit/rules/tests/IgnoreUntilRuleTest.java | 121 ++++++++
.../junit/rules/tests/JUnitRuleTestSuite.java | 33 ++
.../test/junit/rules/tests/RepeatRuleTest.java | 304 +++++++++++++++++++
.../tests/RetryRuleGlobalWithErrorTest.java | 250 +++++++++++++++
.../tests/RetryRuleGlobalWithExceptionTest.java | 254 ++++++++++++++++
.../tests/RetryRuleLocalWithErrorTest.java | 207 +++++++++++++
.../tests/RetryRuleLocalWithExceptionTest.java | 213 +++++++++++++
.../junit/rules/tests/RuleAndClassRuleTest.java | 138 +++++++++
.../test/junit/rules/tests/TestRunner.java | 37 +++
.../junit/support/DefaultIgnoreCondition.java | 57 ++++
.../IgnoreConditionEvaluationException.java | 43 +++
31 files changed, 3438 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/1be4f932/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/ConditionalIgnore.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/ConditionalIgnore.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/ConditionalIgnore.java
new file mode 100755
index 0000000..b409cb1
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/ConditionalIgnore.java
@@ -0,0 +1,49 @@
+/*
+ * 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 com.gemstone.gemfire.test.junit;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import com.gemstone.gemfire.test.junit.support.DefaultIgnoreCondition;
+
+/**
+ * The ConditionalIgnore class is a Java Annotation used to annotated a test suite class test case method in order to
+ * conditionally ignore the test case for a fixed amount of time, or based on a predetermined condition provided by
+ * the IgnoreCondition interface.
+ *
+ * @author John Blum
+ * @see java.lang.annotation.Annotation
+ * @see com.gemstone.gemfire.test.junit.IgnoreCondition
+ * @see com.gemstone.gemfire.test.junit.support.DefaultIgnoreCondition
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.TYPE, ElementType.METHOD })
+@SuppressWarnings("unused")
+public @interface ConditionalIgnore {
+
+ Class extends IgnoreCondition> condition() default DefaultIgnoreCondition.class;
+
+ String until() default "1970-01-01";
+
+ String value() default "";
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/1be4f932/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/IgnoreCondition.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/IgnoreCondition.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/IgnoreCondition.java
new file mode 100755
index 0000000..0caa959
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/IgnoreCondition.java
@@ -0,0 +1,32 @@
+/*
+ * 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 com.gemstone.gemfire.test.junit;
+
+import org.junit.runner.Description;
+
+/**
+ * The IgnoreCondition class...
+ *
+ * @author John Blum
+ * @see org.junit.runner.Description
+ */
+@SuppressWarnings("unused")
+public interface IgnoreCondition {
+
+ boolean evaluate(Description testCaseDescription);
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/1be4f932/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/IgnoreUntil.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/IgnoreUntil.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/IgnoreUntil.java
new file mode 100755
index 0000000..5910d10
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/IgnoreUntil.java
@@ -0,0 +1,49 @@
+/*
+ * 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 com.gemstone.gemfire.test.junit;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import com.gemstone.gemfire.test.junit.support.DefaultIgnoreCondition;
+
+/**
+ * The IgnoreUntil class is a Java Annotation used to annotated a test suite class test case method in order to
+ * conditionally ignore the test case for a fixed amount of time, or based on a predetermined condition provided by
+ * the IgnoreCondition interface.
+ *
+ * @author John Blum
+ * @see java.lang.annotation.Annotation
+ * @see com.gemstone.gemfire.test.junit.IgnoreCondition
+ * @see com.gemstone.gemfire.test.junit.support.DefaultIgnoreCondition
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.TYPE, ElementType.METHOD })
+@SuppressWarnings("unused")
+public @interface IgnoreUntil {
+
+ Class extends IgnoreCondition> condition() default DefaultIgnoreCondition.class;
+
+ String until() default "1970-01-01";
+
+ String value() default "";
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/1be4f932/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/Repeat.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/Repeat.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/Repeat.java
new file mode 100755
index 0000000..5cfa321
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/Repeat.java
@@ -0,0 +1,43 @@
+/*
+ * 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 com.gemstone.gemfire.test.junit;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * The Repeat class is a Java Annotation enabling an annotated test suite class test case method to be repeated
+ * a specified number of iterations.
+ *
+ * @author John Blum
+ * @see java.lang.annotation.Annotation
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.METHOD })
+@SuppressWarnings("unused")
+public @interface Repeat {
+
+ public static int DEFAULT = 1;
+
+ int value() default DEFAULT;
+
+ String property() default "";
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/1be4f932/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/Retry.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/Retry.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/Retry.java
new file mode 100755
index 0000000..65f3cf6
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/Retry.java
@@ -0,0 +1,38 @@
+/*
+ * 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 com.gemstone.gemfire.test.junit;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Java Annotation used to annotate a test suite class test case method in order to
+ * retry it in case of failure up to the specified maximum attempts.
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.METHOD })
+public @interface Retry {
+
+ public static int DEFAULT = 1;
+
+ int value() default DEFAULT;
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/1be4f932/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/ConditionalIgnoreRule.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/ConditionalIgnoreRule.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/ConditionalIgnoreRule.java
new file mode 100755
index 0000000..80898b5
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/ConditionalIgnoreRule.java
@@ -0,0 +1,123 @@
+/*
+ * 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 com.gemstone.gemfire.test.junit.rules;
+
+import java.io.Serializable;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+
+import org.junit.AssumptionViolatedException;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+import com.gemstone.gemfire.test.junit.ConditionalIgnore;
+import com.gemstone.gemfire.test.junit.IgnoreCondition;
+import com.gemstone.gemfire.test.junit.support.IgnoreConditionEvaluationException;
+
+/**
+ * The ConditionalIgnoreRule class...
+ *
+ * @author John Blum
+ * @see org.junit.rules.TestRule
+ * @see org.junit.runner.Description
+ * @see org.junit.runners.model.Statement
+ * @see com.gemstone.gemfire.test.junit.ConditionalIgnore
+ * @see com.gemstone.gemfire.test.junit.IgnoreCondition
+ */
+@SuppressWarnings({ "serial", "unused" })
+public class ConditionalIgnoreRule implements TestRule, Serializable {
+
+ protected static final String DATE_FORMAT_PATTERN = "yyyy-MM-dd";
+ protected static final String DEFAULT_MESSAGE = "Ignoring test case (%1$s) of test class (%2$s)!";
+
+ protected static final DateFormat DATE_FORMAT = new SimpleDateFormat(DATE_FORMAT_PATTERN);
+
+ @Override
+ public Statement apply(final Statement base, final Description description) {
+ return new Statement() {
+ @Override public void evaluate() throws Throwable {
+ ConditionalIgnoreRule.this.evaluate(base, description);
+ }
+ };
+ }
+
+ public final void evaluate(Statement statement, Description description) throws Throwable {
+ throwOnIgnoreTest(statement, description).evaluate();
+ }
+
+ protected Statement throwOnIgnoreTest(Statement statement, Description description) {
+ if (isTest(description)) {
+ boolean ignoreTest = false;
+ String message = "";
+
+ ConditionalIgnore testCaseAnnotation = description.getAnnotation(ConditionalIgnore.class);
+
+ if (testCaseAnnotation != null) {
+ ignoreTest = evaluate(testCaseAnnotation, description);
+ message = testCaseAnnotation.value();
+ }
+ else if (description.getTestClass().isAnnotationPresent(ConditionalIgnore.class)) {
+ ConditionalIgnore testClassAnnotation = description.getTestClass().getAnnotation(ConditionalIgnore.class);
+
+ ignoreTest = evaluate(testClassAnnotation, description);
+ message = testClassAnnotation.value();
+ }
+
+ if (ignoreTest) {
+ throw new AssumptionViolatedException(format(message, description));
+ }
+ }
+
+ return statement;
+ }
+
+ protected boolean isTest(final Description description) {
+ return (description.isSuite() || description.isTest());
+ }
+
+ protected String format(String message, Description description) {
+ message = (!message.isEmpty() ? message : DEFAULT_MESSAGE);
+ return String.format(message, description.getMethodName(), description.getClassName());
+ }
+
+ protected boolean evaluate(ConditionalIgnore conditionalIgnoreAnnotation, Description description) {
+ return (evaluateCondition(conditionalIgnoreAnnotation.condition(), description)
+ || evaluateUntil(conditionalIgnoreAnnotation.until()));
+ }
+
+ protected boolean evaluateCondition(Class extends IgnoreCondition> ignoreConditionType, Description description) {
+ try {
+ return ignoreConditionType.newInstance().evaluate(description);
+ }
+ catch (Exception e) {
+ throw new IgnoreConditionEvaluationException(String.format("failed to evaluate IgnoreCondition: %1$s",
+ ignoreConditionType.getName()), e);
+ }
+ }
+
+ protected boolean evaluateUntil(String timestamp) {
+ try {
+ return DATE_FORMAT.parse(timestamp).after(Calendar.getInstance().getTime());
+ }
+ catch (ParseException e) {
+ return false;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/1be4f932/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/ExpectedTimeoutRule.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/ExpectedTimeoutRule.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/ExpectedTimeoutRule.java
new file mode 100755
index 0000000..7b6d345
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/ExpectedTimeoutRule.java
@@ -0,0 +1,180 @@
+/*
+ * 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 com.gemstone.gemfire.test.junit.rules;
+
+import static org.junit.Assert.assertThat;
+
+import java.util.concurrent.TimeUnit;
+
+import org.hamcrest.Matcher;
+import org.junit.rules.ExpectedException;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * Expect an Exception within a specified timeout.
+ *
+ * @author Kirk Lund
+ * @since 8.2
+ */
+public class ExpectedTimeoutRule implements TestRule {
+
+ /**
+ * @return a Rule that expects no timeout (identical to behavior without this Rule)
+ */
+ public static ExpectedTimeoutRule none() {
+ return new ExpectedTimeoutRule();
+ }
+
+ private ExpectedException delegate;
+ private boolean expectsThrowable;
+ private long minDuration;
+ private long maxDuration;
+ private TimeUnit timeUnit;
+
+ private ExpectedTimeoutRule() {
+ this.delegate = ExpectedException.none();
+ }
+
+ public ExpectedTimeoutRule expectMinimumDuration(final long minDuration) {
+ this.minDuration = minDuration;
+ return this;
+ }
+ public ExpectedTimeoutRule expectMaximumDuration(final long maxDuration) {
+ this.maxDuration = maxDuration;
+ return this;
+ }
+ public ExpectedTimeoutRule expectTimeUnit(final TimeUnit timeUnit) {
+ this.timeUnit = timeUnit;
+ return this;
+ }
+
+ public ExpectedTimeoutRule handleAssertionErrors() {
+ this.delegate.handleAssertionErrors();
+ return this;
+ }
+
+ public ExpectedTimeoutRule handleAssumptionViolatedExceptions() {
+ this.delegate.handleAssumptionViolatedExceptions();
+ return this;
+ }
+
+ /**
+ * Adds {@code matcher} to the list of requirements for any thrown
+ * exception.
+ */
+ public void expect(final Matcher> matcher) {
+ this.delegate.expect(matcher);
+ }
+
+ /**
+ * Adds to the list of requirements for any thrown exception that it should
+ * be an instance of {@code type}
+ */
+ public void expect(final Class extends Throwable> type) {
+ this.delegate.expect(type);
+ this.expectsThrowable = true;
+ }
+
+ /**
+ * Adds to the list of requirements for any thrown exception that it should
+ * contain string {@code substring}
+ */
+ public void expectMessage(final String substring) {
+ this.delegate.expectMessage(substring);
+ }
+
+ /**
+ * Adds {@code matcher} to the list of requirements for the message returned
+ * from any thrown exception.
+ */
+ public void expectMessage(final Matcher matcher) {
+ this.delegate.expectMessage(matcher);
+ }
+
+ /**
+ * Adds {@code matcher} to the list of requirements for the cause of
+ * any thrown exception.
+ */
+ public void expectCause(final Matcher extends Throwable> expectedCause) {
+ this.delegate.expectCause(expectedCause);
+ }
+
+ public boolean expectsTimeout() {
+ return minDuration > 0 || maxDuration > 0;
+ }
+
+ public boolean expectsThrowable() {
+ return expectsThrowable = true;
+ }
+
+ @Override
+ public Statement apply(final Statement base, final Description description) {
+ Statement next = delegate.apply(base, description);
+ return new ExpectedTimeoutStatement(next);
+ }
+
+ private void handleTime(final Long duration) {
+ if (expectsTimeout()) {
+ assertThat(timeUnit.convert(duration, TimeUnit.NANOSECONDS), new TimeMatcher(timeUnit, minDuration, maxDuration));
+ }
+ }
+
+ private static class TimeMatcher extends org.hamcrest.TypeSafeMatcher {
+
+ private final TimeUnit timeUnit;
+ private final long minDuration;
+ private final long maxDuration;
+
+ public TimeMatcher(final TimeUnit timeUnit, final long minDuration, final long maxDuration) {
+ this.timeUnit = timeUnit;
+ this.minDuration = minDuration;
+ this.maxDuration = maxDuration;
+ }
+
+ @Override
+ public boolean matchesSafely(final Long duration) {
+ return duration >= this.minDuration && duration <= this.maxDuration;
+ }
+
+ @Override
+ public void describeTo(final org.hamcrest.Description description) {
+ description.appendText("expects duration to be greater than or equal to ")
+ .appendValue(this.minDuration)
+ .appendText(" and less than or equal to ")
+ .appendValue(this.maxDuration)
+ .appendText(" ")
+ .appendValue(this.timeUnit);
+ }
+ }
+
+ private class ExpectedTimeoutStatement extends Statement {
+ private final Statement next;
+
+ public ExpectedTimeoutStatement(final Statement base) {
+ next = base;
+ }
+
+ @Override
+ public void evaluate() throws Throwable {
+ long start = System.nanoTime();
+ next.evaluate();
+ handleTime(System.nanoTime() - start);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/1be4f932/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/IgnoreUntilRule.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/IgnoreUntilRule.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/IgnoreUntilRule.java
new file mode 100755
index 0000000..bf4ec3f
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/IgnoreUntilRule.java
@@ -0,0 +1,123 @@
+/*
+ * 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 com.gemstone.gemfire.test.junit.rules;
+
+import java.io.Serializable;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+
+import org.junit.AssumptionViolatedException;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+import com.gemstone.gemfire.test.junit.IgnoreUntil;
+import com.gemstone.gemfire.test.junit.IgnoreCondition;
+import com.gemstone.gemfire.test.junit.support.IgnoreConditionEvaluationException;
+
+/**
+ * The IgnoreUntilRule class...
+ *
+ * @author John Blum
+ * @see org.junit.rules.TestRule
+ * @see org.junit.runner.Description
+ * @see org.junit.runners.model.Statement
+ * @see com.gemstone.gemfire.test.junit.IgnoreUntil
+ * @see com.gemstone.gemfire.test.junit.IgnoreCondition
+ */
+@SuppressWarnings({ "serial", "unused" })
+public class IgnoreUntilRule implements TestRule, Serializable {
+
+ protected static final String DATE_FORMAT_PATTERN = "yyyy-MM-dd";
+ protected static final String DEFAULT_MESSAGE = "Ignoring test case (%1$s) of test class (%2$s)!";
+
+ protected static final DateFormat DATE_FORMAT = new SimpleDateFormat(DATE_FORMAT_PATTERN);
+
+ @Override
+ public Statement apply(final Statement base, final Description description) {
+ return new Statement() {
+ @Override public void evaluate() throws Throwable {
+ IgnoreUntilRule.this.evaluate(base, description);
+ }
+ };
+ }
+
+ public final void evaluate(Statement statement, Description description) throws Throwable {
+ throwOnIgnoreTest(statement, description).evaluate();
+ }
+
+ protected Statement throwOnIgnoreTest(Statement statement, Description description) {
+ if (isTest(description)) {
+ boolean ignoreTest = false;
+ String message = "";
+
+ IgnoreUntil testCaseAnnotation = description.getAnnotation(IgnoreUntil.class);
+
+ if (testCaseAnnotation != null) {
+ ignoreTest = evaluate(testCaseAnnotation, description);
+ message = testCaseAnnotation.value();
+ }
+ else if (description.getTestClass().isAnnotationPresent(IgnoreUntil.class)) {
+ IgnoreUntil testClassAnnotation = description.getTestClass().getAnnotation(IgnoreUntil.class);
+
+ ignoreTest = evaluate(testClassAnnotation, description);
+ message = testClassAnnotation.value();
+ }
+
+ if (ignoreTest) {
+ throw new AssumptionViolatedException(format(message, description));
+ }
+ }
+
+ return statement;
+ }
+
+ protected boolean isTest(final Description description) {
+ return (description.isSuite() || description.isTest());
+ }
+
+ protected String format(String message, Description description) {
+ message = (!message.isEmpty() ? message : DEFAULT_MESSAGE);
+ return String.format(message, description.getMethodName(), description.getClassName());
+ }
+
+ protected boolean evaluate(IgnoreUntil conditionalIgnoreAnnotation, Description description) {
+ return (evaluateCondition(conditionalIgnoreAnnotation.condition(), description)
+ || evaluateUntil(conditionalIgnoreAnnotation.until()));
+ }
+
+ protected boolean evaluateCondition(Class extends IgnoreCondition> ignoreConditionType, Description description) {
+ try {
+ return ignoreConditionType.newInstance().evaluate(description);
+ }
+ catch (Exception e) {
+ throw new IgnoreConditionEvaluationException(String.format("failed to evaluate IgnoreCondition: %1$s",
+ ignoreConditionType.getName()), e);
+ }
+ }
+
+ protected boolean evaluateUntil(String timestamp) {
+ try {
+ return DATE_FORMAT.parse(timestamp).after(Calendar.getInstance().getTime());
+ }
+ catch (ParseException e) {
+ return false;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/1be4f932/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RepeatRule.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RepeatRule.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RepeatRule.java
new file mode 100755
index 0000000..7bfe538
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RepeatRule.java
@@ -0,0 +1,81 @@
+/*
+ * 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 com.gemstone.gemfire.test.junit.rules;
+
+import java.io.Serializable;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+import com.gemstone.gemfire.test.junit.Repeat;
+
+/**
+ * The RepeatRule class is a JUnit TestRule that enables an appropriately @Repeat annotated test case method
+ * to be repeated a specified number of times.
+ *
+ * @author John Blum
+ * @see org.junit.rules.TestRule
+ * @see org.junit.runner.Description
+ * @see org.junit.runners.model.Statement
+ */
+@SuppressWarnings({ "serial", "unused" })
+public class RepeatRule implements TestRule, Serializable {
+
+ protected static final int DEFAULT_REPETITIONS = 1;
+
+ @Override
+ public Statement apply(final Statement statement, final Description description) {
+ return new Statement() {
+ @Override public void evaluate() throws Throwable {
+ RepeatRule.this.evaluate(statement, description);
+ }
+ };
+ }
+
+ protected void evaluate(final Statement statement, final Description description) throws Throwable {
+ if (isTest(description)) {
+ Repeat repeat = description.getAnnotation(Repeat.class);
+
+ for (int count = 0, repetitions = getRepetitions(repeat); count < repetitions; count++) {
+ statement.evaluate();
+ }
+ }
+ }
+
+ private int getRepetitions(final Repeat repeat) {
+ int repetitions = DEFAULT_REPETITIONS;
+
+ if (repeat != null) {
+ if (!"".equals(repeat.property())) {
+ repetitions = Integer.getInteger(repeat.property(), DEFAULT_REPETITIONS);
+ } else {
+ repetitions = repeat.value();
+ }
+ }
+
+ if (repetitions < 1) {
+ throw new IllegalArgumentException("Repeat value must be a positive integer");
+ }
+
+ return repetitions;
+ }
+
+ private boolean isTest(final Description description) {
+ return (description.isSuite() || description.isTest());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/1be4f932/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRule.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRule.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRule.java
new file mode 100755
index 0000000..4a26d5e
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/RetryRule.java
@@ -0,0 +1,181 @@
+/*
+ * 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 com.gemstone.gemfire.test.junit.rules;
+
+import java.io.Serializable;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import com.gemstone.gemfire.test.junit.Retry;
+
+/**
+ * JUnit Rule that enables retrying a failed test up to a maximum number of retries.
+ *
+ * RetryRule can be used globally for all tests in a test case by specifying a
+ * retryCount when instantiating it:
+ *
+ * @Rule
+ * public final RetryRule retryRule = new RetryRule(3);
+ *
+ * @Test
+ * public void shouldBeRetriedUntilPasses() {
+ * ...
+ * }
+ *
+ *
+ * The above will result in 3 retries for every test in the test case.
+ *
+ * RetryRule can be used locally for specific tests by annotating the test
+ * method with @Rule and specifying a retryCount for that test:
+ *
+ * @Rule
+ * public final RetryRule retryRule = new RetryRule();
+ *
+ * @Test
+ * @Retry(3)
+ * public void shouldBeRetriedUntilPasses() {
+ * ...
+ * }
+ *
+ *
+ * This version of RetryRule will retry a test that fails because of any kind
+ * of Throwable.
+ */
+@SuppressWarnings("serial")
+public class RetryRule implements TestRule, Serializable {
+
+ /**
+ * Enables printing of failures to System.err even if test passes on a retry
+ */
+ private static final boolean LOG = false;
+
+ private final AbstractRetryRule implementation;
+
+ public RetryRule() {
+ this.implementation = new LocalRetryRule();
+ }
+
+ public RetryRule(final int retryCount) {
+ this.implementation = new GlobalRetryRule(retryCount);
+ }
+
+ @Override
+ public Statement apply(final Statement base, final Description description) {
+ return this.implementation.apply(base, description);
+ }
+
+ protected abstract class AbstractRetryRule implements TestRule {
+ protected AbstractRetryRule() {
+ }
+ protected void evaluate(final Statement base, final Description description, final int retryCount) throws Throwable {
+ if (retryCount == 0) {
+
+ }
+ Throwable caughtThrowable = null;
+
+ for (int count = 0; count < retryCount; count++) {
+ try {
+ base.evaluate();
+ return;
+ } catch (Throwable t) {
+ caughtThrowable = t;
+ debug(description.getDisplayName() + ": run " + (count + 1) + " failed");
+ }
+ }
+
+ debug(description.getDisplayName() + ": giving up after " + retryCount + " failures");
+ throw caughtThrowable;
+ }
+ private void debug(final String message) {
+ if (LOG) {
+ System.err.println(message);
+ }
+ }
+ }
+
+ /**
+ * Implementation of RetryRule for all test methods in a test case
+ */
+ protected class GlobalRetryRule extends AbstractRetryRule {
+
+ private final int retryCount;
+
+ protected GlobalRetryRule(final int retryCount) {
+ if (retryCount < 1) {
+ throw new IllegalArgumentException("Retry count must be greater than zero");
+ }
+ this.retryCount = retryCount;
+ }
+
+ @Override
+ public Statement apply(final Statement base, final Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ GlobalRetryRule.this.evaluatePerCase(base, description);
+ }
+ };
+ }
+
+ protected void evaluatePerCase(final Statement base, final Description description) throws Throwable {
+ evaluate(base, description, this.retryCount);
+ }
+ }
+
+ /**
+ * Implementation of RetryRule for test methods annotated with Retry
+ */
+ protected class LocalRetryRule extends AbstractRetryRule {
+
+ protected LocalRetryRule() {
+ }
+
+ @Override
+ public Statement apply(final Statement base, final Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ LocalRetryRule.this.evaluatePerTest(base, description);
+ }
+ };
+ }
+
+ protected void evaluatePerTest(final Statement base, final Description description) throws Throwable {
+ if (isTest(description)) {
+ Retry retry = description.getAnnotation(Retry.class);
+ int retryCount = getRetryCount(retry);
+ evaluate(base, description, retryCount);
+ }
+ }
+
+ private int getRetryCount(final Retry retry) {
+ int retryCount = Retry.DEFAULT;
+
+ if (retry != null) {
+ retryCount = retry.value();
+ }
+
+ return retryCount;
+ }
+
+ private boolean isTest(final Description description) {
+ return (description.isSuite() || description.isTest());
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/1be4f932/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/SerializableExternalResource.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/SerializableExternalResource.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/SerializableExternalResource.java
new file mode 100755
index 0000000..37d8eb5
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/SerializableExternalResource.java
@@ -0,0 +1,107 @@
+/*
+ * 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 com.gemstone.gemfire.test.junit.rules;
+
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * Serializable version of ExternalResource JUnit Rule. JUnit lifecycle is not
+ * executed in remote JVMs. The after() callback has a throws-clause
+ * that matches before().
+ *
+ * Implementation copied from org.junit.rules.ExternalResource.
+ *
+ * @author Kirk Lund
+ */
+@SuppressWarnings("serial")
+public abstract class SerializableExternalResource implements SerializableTestRule {
+
+ @Override
+ public Statement apply(final Statement base, final Description description) {
+ if (description.isTest()) {
+ return statement(base);
+ } else if (description.isSuite()) {
+ return statementClass(base);
+ }
+ return base;
+ }
+
+ private Statement statement(final Statement base) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ before();
+ try {
+ base.evaluate();
+ } finally {
+ after();
+ }
+ }
+ };
+ }
+
+ private Statement statementClass(final Statement base) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ beforeClass();
+ try {
+ base.evaluate();
+ } finally {
+ afterClass();
+ }
+ }
+ };
+ }
+
+ /**
+ * Override to set up your specific external resource.
+ *
+ * @throws Throwable if setup fails (which will disable {@code after}
+ */
+ protected void before() throws Throwable {
+ // do nothing
+ }
+
+ /**
+ * Override to tear down your specific external resource.
+ *
+ * @throws Throwable if teardown fails (which will disable {@code after}
+ */
+ protected void after() throws Throwable {
+ // do nothing
+ }
+
+ /**
+ * Override to set up your specific external resource.
+ *
+ * @throws Throwable if setup fails (which will disable {@code after}
+ */
+ protected void beforeClass() throws Throwable {
+ // do nothing
+ }
+
+ /**
+ * Override to tear down your specific external resource.
+ *
+ * @throws Throwable if teardown fails (which will disable {@code after}
+ */
+ protected void afterClass() throws Throwable {
+ // do nothing
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/1be4f932/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/SerializableRuleChain.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/SerializableRuleChain.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/SerializableRuleChain.java
new file mode 100755
index 0000000..936345e
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/SerializableRuleChain.java
@@ -0,0 +1,119 @@
+/*
+ * 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 com.gemstone.gemfire.test.junit.rules;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * Serializable version of TemporaryFolder JUnit Rule. JUnit lifecycle is not
+ * executed in remote JVMs.
+ *
+ * Implementation copied from org.junit.rules.RuleChain.
+ *
+ * The SerializableRuleChain rule allows ordering of TestRules. You create a
+ * {@code RuleChain} with {@link #outerRule(TestRule)} and subsequent calls of
+ * {@link #around(TestRule)}:
+ *
+ *
+ * public static class UseRuleChain {
+ * @Rule
+ * public RuleChain chain= RuleChain
+ * .outerRule(new LoggingRule("outer rule")
+ * .around(new LoggingRule("middle rule")
+ * .around(new LoggingRule("inner rule");
+ *
+ * @Test
+ * public void example() {
+ * assertTrue(true);
+ * }
+ * }
+ *
+ *
+ * writes the log
+ *
+ *
+ * starting outer rule
+ * starting middle rule
+ * starting inner rule
+ * finished inner rule
+ * finished middle rule
+ * finished outer rule
+ *
+ *
+ * @author Kirk Lund
+ */
+@SuppressWarnings("serial")
+public class SerializableRuleChain implements SerializableTestRule {
+ private static final SerializableRuleChain EMPTY_CHAIN = new SerializableRuleChain(Collections.emptyList());
+
+ private transient List rulesStartingWithInnerMost;
+
+ /**
+ * Returns a {@code SerializableRuleChain} without a {@link TestRule}. This method may
+ * be the starting point of a {@code SerializableRuleChain}.
+ *
+ * @return a {@code SerializableRuleChain} without a {@link TestRule}.
+ */
+ public static SerializableRuleChain emptyRuleChain() {
+ return EMPTY_CHAIN;
+ }
+
+ /**
+ * Returns a {@code SerializableRuleChain} with a single {@link TestRule}. This method
+ * is the usual starting point of a {@code SerializableRuleChain}.
+ *
+ * @param outerRule the outer rule of the {@code SerializableRuleChain}.
+ * @return a {@code SerializableRuleChain} with a single {@link TestRule}.
+ */
+ public static SerializableRuleChain outerRule(TestRule outerRule) {
+ return emptyRuleChain().around(outerRule);
+ }
+
+ private SerializableRuleChain(List rules) {
+ this.rulesStartingWithInnerMost = rules;
+ }
+
+ /**
+ * Create a new {@code SerializableRuleChain}, which encloses the {@code nextRule} with
+ * the rules of the current {@code SerializableRuleChain}.
+ *
+ * @param enclosedRule the rule to enclose.
+ * @return a new {@code SerializableRuleChain}.
+ */
+ public SerializableRuleChain around(TestRule enclosedRule) {
+ List rulesOfNewChain = new ArrayList();
+ rulesOfNewChain.add(enclosedRule);
+ rulesOfNewChain.addAll(rulesStartingWithInnerMost);
+ return new SerializableRuleChain(rulesOfNewChain);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Statement apply(Statement base, Description description) {
+ for (TestRule each : rulesStartingWithInnerMost) {
+ base = each.apply(base, description);
+ }
+ return base;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/1be4f932/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/SerializableTemporaryFolder.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/SerializableTemporaryFolder.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/SerializableTemporaryFolder.java
new file mode 100755
index 0000000..0e796b3
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/SerializableTemporaryFolder.java
@@ -0,0 +1,70 @@
+/*
+ * 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 com.gemstone.gemfire.test.junit.rules;
+
+import java.io.File;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.lang.reflect.Field;
+
+import org.junit.rules.TemporaryFolder;
+
+/**
+ * Serializable version of TemporaryFolder JUnit Rule. JUnit lifecycle is not
+ * executed in remote JVMs.
+ *
+ * @author Kirk Lund
+ */
+@SuppressWarnings("serial")
+public class SerializableTemporaryFolder extends TemporaryFolder implements SerializableTestRule {
+
+ private void writeObject(final ObjectOutputStream out) throws Exception {
+ writeParentFolder(out);
+ writeFolder(out);
+ }
+
+ private void readObject(final ObjectInputStream in) throws Exception {
+ readParentFolder(in);
+ readFolder(in);
+ }
+
+ private void readParentFolder(final ObjectInputStream in) throws Exception {
+ final Field parentFolderField = TemporaryFolder.class.getDeclaredField("parentFolder");
+ parentFolderField.setAccessible(true);
+ parentFolderField.set(this, (File) in.readObject());
+ }
+
+ private void readFolder(final ObjectInputStream in) throws Exception {
+ final Field folderField = TemporaryFolder.class.getDeclaredField("folder");
+ folderField.setAccessible(true);
+ folderField.set(this, (File) in.readObject());
+ }
+
+ private void writeParentFolder(final ObjectOutputStream out) throws Exception {
+ final Field parentFolderField = TemporaryFolder.class.getDeclaredField("parentFolder");
+ parentFolderField.setAccessible(true);
+ final File parentFolderFieldValue = (File) parentFolderField.get(this);
+ out.writeObject(parentFolderFieldValue);
+ }
+
+ private void writeFolder(final ObjectOutputStream out) throws Exception {
+ final Field folderField = TemporaryFolder.class.getDeclaredField("folder");
+ folderField.setAccessible(true);
+ final File folderFieldValue = (File) folderField.get(this);
+ out.writeObject(folderFieldValue);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/1be4f932/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/SerializableTestName.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/SerializableTestName.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/SerializableTestName.java
new file mode 100755
index 0000000..1fd255f
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/SerializableTestName.java
@@ -0,0 +1,54 @@
+/*
+ * 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 com.gemstone.gemfire.test.junit.rules;
+
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.lang.reflect.Field;
+
+import org.junit.rules.TestName;
+
+/**
+ * Serializable version of TestName JUnit Rule. JUnit lifecycle is not
+ * executed in remote JVMs.
+ *
+ * @author Kirk Lund
+ */
+@SuppressWarnings("serial")
+public class SerializableTestName extends TestName implements SerializableTestRule {
+
+ private void writeObject(final ObjectOutputStream out) throws Exception {
+ writeName(out);
+ }
+
+ private void readObject(final ObjectInputStream in) throws Exception {
+ readName(in);
+ }
+
+ private void writeName(final ObjectOutputStream out) throws Exception {
+ final Field nameField = TestName.class.getDeclaredField("name");
+ nameField.setAccessible(true);
+ final String nameValue = (String) nameField.get(this);
+ out.writeObject(nameValue);
+ }
+
+ private void readName(final ObjectInputStream in) throws Exception {
+ Field nameField = TestName.class.getDeclaredField("name");
+ nameField.setAccessible(true);
+ nameField.set(this, (String) in.readObject());
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/1be4f932/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/SerializableTestRule.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/SerializableTestRule.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/SerializableTestRule.java
new file mode 100755
index 0000000..354c38a
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/SerializableTestRule.java
@@ -0,0 +1,33 @@
+/*
+ * 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 com.gemstone.gemfire.test.junit.rules;
+
+import java.io.Serializable;
+
+import org.junit.rules.TestRule;
+
+/**
+ * Serializable version of JUnit TestRule. JUnit lifecycle is not
+ * executed in remote JVMs.
+ *
+ * The simplest way to satisfy this interface is to apply transient
+ * to every instance field.
+ *
+ * @author Kirk Lund
+ */
+public interface SerializableTestRule extends Serializable, TestRule {
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/1be4f932/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/SerializableTestWatcher.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/SerializableTestWatcher.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/SerializableTestWatcher.java
new file mode 100755
index 0000000..5bcf686
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/SerializableTestWatcher.java
@@ -0,0 +1,29 @@
+/*
+ * 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 com.gemstone.gemfire.test.junit.rules;
+
+import org.junit.rules.TestWatcher;
+
+/**
+ * Serializable version of TestWatcher JUnit Rule. JUnit lifecycle is not
+ * executed in remote JVMs.
+ *
+ * @author Kirk Lund
+ */
+@SuppressWarnings("serial")
+public class SerializableTestWatcher extends TestWatcher implements SerializableTestRule {
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/1be4f932/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/SerializableTimeout.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/SerializableTimeout.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/SerializableTimeout.java
new file mode 100755
index 0000000..3136a1c
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/SerializableTimeout.java
@@ -0,0 +1,119 @@
+/*
+ * 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 com.gemstone.gemfire.test.junit.rules;
+
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.lang.reflect.Field;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.rules.TemporaryFolder;
+import org.junit.rules.TestName;
+import org.junit.rules.Timeout;
+
+/**
+ * Serializable version of Timeout JUnit Rule. JUnit lifecycle is not
+ * executed in remote JVMs.
+ *
+ * @author Kirk Lund
+ */
+@SuppressWarnings("serial")
+public class SerializableTimeout extends Timeout implements SerializableTestRule {
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public SerializableTimeout(final long timeout, final TimeUnit timeUnit) {
+ super(timeout, timeUnit);
+ }
+
+ protected SerializableTimeout(final Builder builder) {
+ super(builder);
+ }
+
+ public static class Builder extends Timeout.Builder {
+
+ protected Builder() {
+ super();
+ }
+
+ @Override
+ public SerializableTimeout build() {
+ return new SerializableTimeout(this);
+ }
+ }
+
+ private void writeObject(final ObjectOutputStream out) throws Exception {
+ writeTimeout(out);
+ writeTimeUnit(out);
+ writeLookForStuckThread(out);
+ }
+
+ private void readObject(final ObjectInputStream in) throws Exception {
+ readTimeout(in);
+ readTimeUnit(in);
+ readLookForStuckThread(in);
+ }
+
+ private void writeTimeout(final ObjectOutputStream out) throws Exception {
+ final Field timeoutField = TestName.class.getDeclaredField("timeout");
+ timeoutField.setAccessible(true);
+ final Long timeoutValue = (Long) timeoutField.get(this);
+ out.writeLong(timeoutValue);
+ }
+
+ private void writeTimeUnit(final ObjectOutputStream out) throws Exception {
+ final Field timeoutField = TestName.class.getDeclaredField("timeUnit");
+ timeoutField.setAccessible(true);
+ final TimeUnit timeoutValue = (TimeUnit) timeoutField.get(this);
+ out.writeObject(timeoutValue);
+ }
+
+ private void writeLookForStuckThread(final ObjectOutputStream out) throws Exception {
+ try {
+ final Field lookForStuckThreadField = TemporaryFolder.class.getDeclaredField("lookForStuckThread");
+ lookForStuckThreadField.setAccessible(true);
+ final Boolean lookForStuckThreadValue = (Boolean) lookForStuckThreadField.get(this);
+ out.writeBoolean(lookForStuckThreadValue);
+ } catch (NoSuchFieldException e) {
+ out.writeBoolean(false);
+ }
+ }
+
+ private void readTimeout(final ObjectInputStream in) throws Exception {
+ Field timeoutField = TestName.class.getDeclaredField("timeout");
+ timeoutField.setAccessible(true);
+ timeoutField.set(this, (Long) in.readObject());
+ }
+
+ private void readTimeUnit(final ObjectInputStream in) throws Exception {
+ Field timeUnitField = TestName.class.getDeclaredField("timeUnit");
+ timeUnitField.setAccessible(true);
+ timeUnitField.set(this, (TimeUnit) in.readObject());
+ }
+
+ private void readLookForStuckThread(final ObjectInputStream in) throws Exception {
+ try {
+ final Field lookForStuckThreadField = TemporaryFolder.class.getDeclaredField("lookForStuckThread");
+ lookForStuckThreadField.setAccessible(true);
+ lookForStuckThreadField.set(this, (Boolean) in.readObject());
+ } catch (NoSuchFieldException e) {
+ final boolean value = (Boolean) in.readObject();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/1be4f932/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/examples/RepeatingTestCasesExampleTest.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/examples/RepeatingTestCasesExampleTest.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/examples/RepeatingTestCasesExampleTest.java
new file mode 100755
index 0000000..5ee647b
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/examples/RepeatingTestCasesExampleTest.java
@@ -0,0 +1,94 @@
+/*
+ * 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 com.gemstone.gemfire.test.junit.rules.examples;
+
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.assertThat;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import com.gemstone.gemfire.test.junit.Repeat;
+import com.gemstone.gemfire.test.junit.categories.UnitTest;
+import com.gemstone.gemfire.test.junit.rules.RepeatRule;
+
+/**
+ * The RepeatingTestCasesExampleTest class is a test suite of test cases testing the contract and functionality
+ * of the JUnit @Repeat annotation on a test suite class test case methods.
+ *
+ * @author John Blum
+ * @see org.junit.Test
+ * @see com.gemstone.gemfire.test.junit.Repeat
+ * @see com.gemstone.gemfire.test.junit.rules.RepeatRule
+ */
+@Category(UnitTest.class)
+public class RepeatingTestCasesExampleTest {
+
+ private static AtomicInteger repeatOnceCounter = new AtomicInteger(0);
+ private static AtomicInteger repeatOnlyOnceCounter = new AtomicInteger(0);
+ private static AtomicInteger repeatTenTimesCounter = new AtomicInteger(0);
+ private static AtomicInteger repeatTwiceCounter = new AtomicInteger(0);
+
+ @Rule
+ public RepeatRule repeatRule = new RepeatRule();
+
+ @BeforeClass
+ public static void setupBeforeClass() {
+ System.setProperty("tdd.example.test.case.two.repetitions", "2");
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() {
+ assertThat(repeatOnceCounter.get(), is(equalTo(1)));
+ assertThat(repeatOnlyOnceCounter.get(), is(equalTo(1)));
+ assertThat(repeatTenTimesCounter.get(), is(equalTo(10)));
+ assertThat(repeatTwiceCounter.get(), is(equalTo(2)));
+ }
+
+ @Test
+ @Repeat
+ public void repeatOnce() {
+ repeatOnceCounter.incrementAndGet();
+ assertThat(repeatOnceCounter.get() <= 1, is(true));
+ }
+
+ @Test
+ @Repeat(property = "tdd.example.test.case.with.non-existing.system.property")
+ public void repeatOnlyOnce() {
+ repeatOnlyOnceCounter.incrementAndGet();
+ assertThat(repeatOnlyOnceCounter.get() <= 1, is(true));
+ }
+
+ @Test
+ @Repeat(10)
+ public void repeatTenTimes() {
+ repeatTenTimesCounter.incrementAndGet();
+ assertThat(repeatTenTimesCounter.get() <= 10, is(true));
+ }
+
+ @Test
+ @Repeat(property = "tdd.example.test.case.two.repetitions")
+ public void repeatTwiceCounter() {
+ repeatTwiceCounter.incrementAndGet();
+ assertThat(repeatTwiceCounter.get() <= 2, is(true));
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/1be4f932/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/examples/RetryRuleExampleTest.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/examples/RetryRuleExampleTest.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/examples/RetryRuleExampleTest.java
new file mode 100755
index 0000000..f6d70a2
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/examples/RetryRuleExampleTest.java
@@ -0,0 +1,43 @@
+/*
+ * 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 com.gemstone.gemfire.test.junit.rules.examples;
+
+import static org.assertj.core.api.Assertions.*;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+
+import com.gemstone.gemfire.test.junit.categories.UnitTest;
+import com.gemstone.gemfire.test.junit.rules.RetryRule;
+
+@Category(UnitTest.class)
+public class RetryRuleExampleTest {
+
+ @Rule
+ public final transient RetryRule retry = new RetryRule(2);
+
+ private static int count = 0;
+
+ @Test
+ public void unreliableTestWithRaceConditions() {
+ count++;
+ if (count < 2) {
+ assertThat(count).isEqualTo(2); // doomed to fail
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/1be4f932/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/ExpectedTimeoutRuleTest.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/ExpectedTimeoutRuleTest.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/ExpectedTimeoutRuleTest.java
new file mode 100755
index 0000000..b67d1eb
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/ExpectedTimeoutRuleTest.java
@@ -0,0 +1,214 @@
+/*
+ * 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 com.gemstone.gemfire.test.junit.rules.tests;
+
+import static com.gemstone.gemfire.test.junit.rules.tests.TestRunner.*;
+import static org.assertj.core.api.Assertions.*;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.Result;
+import org.junit.runner.notification.Failure;
+
+import com.gemstone.gemfire.test.junit.categories.UnitTest;
+import com.gemstone.gemfire.test.junit.rules.ExpectedTimeoutRule;
+
+/**
+ * Unit tests for ExpectedTimeout JUnit Rule.
+ *
+ * @author Kirk Lund
+ * @since 8.2
+ */
+@Category(UnitTest.class)
+public class ExpectedTimeoutRuleTest {
+
+ @Test
+ public void passesUnused() {
+ Result result = runTest(PassingTestShouldPassWhenUnused.class);
+
+ assertThat(result.wasSuccessful()).isTrue();
+ }
+
+ @Test
+ public void failsWithoutExpectedException() {
+ Result result = runTest(FailsWithoutExpectedException.class);
+
+ assertThat(result.wasSuccessful()).isFalse();
+
+ List failures = result.getFailures();
+ assertThat(failures.size()).as("Failures: " + failures).isEqualTo(1);
+
+ Failure failure = failures.get(0);
+ assertThat(failure.getException()).isExactlyInstanceOf(AssertionError.class).hasMessage("Expected test to throw an instance of " + TimeoutException.class.getName());
+ }
+
+ @Test
+ public void failsWithoutExpectedTimeoutException() {
+ Result result = runTest(FailsWithoutExpectedTimeoutException.class);
+
+ assertThat(result.wasSuccessful()).isFalse();
+
+ List failures = result.getFailures();
+ assertThat(failures.size()).as("Failures: " + failures).isEqualTo(1);
+
+ Failure failure = failures.get(0);
+ assertThat(failure.getException()).isExactlyInstanceOf(AssertionError.class).hasMessage("Expected test to throw (an instance of " + TimeoutException.class.getName() + " and exception with message a string containing \"" + FailsWithoutExpectedTimeoutException.message + "\")");
+ }
+
+ @Test
+ public void failsWithExpectedTimeoutButWrongError() {
+ Result result = runTest(FailsWithExpectedTimeoutButWrongError.class);
+
+ assertThat(result.wasSuccessful()).isFalse();
+
+ List failures = result.getFailures();
+ assertThat(failures.size()).as("Failures: " + failures).isEqualTo(1);
+
+ Failure failure = failures.get(0);
+ String expectedMessage =
+ "\n" +
+ "Expected: (an instance of java.util.concurrent.TimeoutException and exception with message a string containing \"this is a message for FailsWithExpectedTimeoutButWrongError\")" +
+ "\n" +
+ " " +
+ "but: an instance of java.util.concurrent.TimeoutException is a java.lang.NullPointerException";
+ assertThat(failure.getException()).isExactlyInstanceOf(AssertionError.class).hasMessageContaining(expectedMessage);
+ }
+
+ @Test
+ public void passesWithExpectedTimeoutAndTimeoutException() {
+ Result result = runTest(PassesWithExpectedTimeoutAndTimeoutException.class);
+
+ assertThat(result.wasSuccessful()).isTrue();
+ }
+
+ @Test
+ public void failsWhenTimeoutIsEarly() {
+ Result result = runTest(FailsWhenTimeoutIsEarly.class);
+
+ assertThat(result.wasSuccessful()).isFalse();
+
+ List failures = result.getFailures();
+ assertThat(failures.size()).as("Failures: " + failures).isEqualTo(1);
+
+ Failure failure = failures.get(0);
+ assertThat(failure.getException()).isExactlyInstanceOf(AssertionError.class).hasMessage("Expected test to throw (an instance of " + TimeoutException.class.getName() + " and exception with message a string containing \"" + FailsWhenTimeoutIsEarly.message + "\")");
+ }
+
+ @Test
+ public void failsWhenTimeoutIsLate() {
+ Result result = runTest(FailsWhenTimeoutIsLate.class);
+
+ assertThat(result.wasSuccessful()).isFalse();
+
+ List failures = result.getFailures();
+ assertThat(failures.size()).as("Failures: " + failures).isEqualTo(1);
+
+ Failure failure = failures.get(0);
+ assertThat(failure.getException()).isExactlyInstanceOf(AssertionError.class).hasMessage("Expected test to throw (an instance of " + TimeoutException.class.getName() + " and exception with message a string containing \"" + FailsWhenTimeoutIsLate.message + "\")");
+ }
+
+ public static class AbstractExpectedTimeoutRuleTest {
+ @Rule
+ public ExpectedTimeoutRule timeout = ExpectedTimeoutRule.none();
+ }
+
+ public static class PassingTestShouldPassWhenUnused extends AbstractExpectedTimeoutRuleTest {
+ @Test
+ public void passesUnused() throws Exception {
+ }
+ }
+
+ public static class FailsWithoutExpectedException extends AbstractExpectedTimeoutRuleTest {
+ @Test
+ public void failsWithoutExpectedException() throws Exception {
+ timeout.expect(TimeoutException.class);
+ }
+ }
+
+ public static class FailsWithoutExpectedTimeoutException extends AbstractExpectedTimeoutRuleTest {
+ public static final String message = "this is a message for FailsWithoutExpectedTimeoutException";
+ @Test
+ public void failsWithoutExpectedTimeoutAndTimeoutException() throws Exception {
+ timeout.expect(TimeoutException.class);
+ timeout.expectMessage(message);
+ timeout.expectMinimumDuration(10);
+ timeout.expectMaximumDuration(1000);
+ timeout.expectTimeUnit(TimeUnit.MILLISECONDS);
+ Thread.sleep(100);
+ }
+ }
+
+ public static class FailsWithExpectedTimeoutButWrongError extends AbstractExpectedTimeoutRuleTest {
+ public static final String message = "this is a message for FailsWithExpectedTimeoutButWrongError";
+ @Test
+ public void failsWithExpectedTimeoutButWrongError() throws Exception {
+ timeout.expect(TimeoutException.class);
+ timeout.expectMessage(message);
+ timeout.expectMinimumDuration(10);
+ timeout.expectMaximumDuration(1000);
+ timeout.expectTimeUnit(TimeUnit.MILLISECONDS);
+ Thread.sleep(100);
+ throw new NullPointerException();
+ }
+ }
+
+ public static class PassesWithExpectedTimeoutAndTimeoutException extends AbstractExpectedTimeoutRuleTest {
+ public static final String message = "this is a message for PassesWithExpectedTimeoutAndTimeoutException";
+ public static final Class exceptionClass = TimeoutException.class;
+ @Test
+ public void passesWithExpectedTimeoutAndTimeoutException() throws Exception {
+ timeout.expect(exceptionClass);
+ timeout.expectMessage(message);
+ timeout.expectMinimumDuration(10);
+ timeout.expectMaximumDuration(1000);
+ timeout.expectTimeUnit(TimeUnit.MILLISECONDS);
+ Thread.sleep(100);
+ throw new TimeoutException(message);
+ }
+ }
+
+ public static class FailsWhenTimeoutIsEarly extends AbstractExpectedTimeoutRuleTest {
+ public static final String message = "this is a message for FailsWhenTimeoutIsEarly";
+ @Test
+ public void failsWhenTimeoutIsEarly() throws Exception {
+ timeout.expect(TimeoutException.class);
+ timeout.expectMessage(message);
+ timeout.expectMinimumDuration(1000);
+ timeout.expectMaximumDuration(2000);
+ timeout.expectTimeUnit(TimeUnit.MILLISECONDS);
+ Thread.sleep(10);
+ }
+ }
+
+ public static class FailsWhenTimeoutIsLate extends AbstractExpectedTimeoutRuleTest {
+ public static final String message = "this is a message for FailsWhenTimeoutIsLate";
+ @Test
+ public void failsWhenTimeoutIsLate() throws Exception {
+ timeout.expect(TimeoutException.class);
+ timeout.expectMessage(message);
+ timeout.expectMinimumDuration(10);
+ timeout.expectMaximumDuration(20);
+ timeout.expectTimeUnit(TimeUnit.MILLISECONDS);
+ Thread.sleep(100);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/1be4f932/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/IgnoreUntilRuleTest.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/IgnoreUntilRuleTest.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/IgnoreUntilRuleTest.java
new file mode 100755
index 0000000..a984d1d
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/IgnoreUntilRuleTest.java
@@ -0,0 +1,121 @@
+/*
+ * 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 com.gemstone.gemfire.test.junit.rules.tests;
+
+import static com.gemstone.gemfire.test.junit.rules.tests.TestRunner.*;
+import static org.assertj.core.api.Assertions.*;
+
+import java.util.List;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.Result;
+import org.junit.runner.notification.Failure;
+
+import com.gemstone.gemfire.test.junit.IgnoreUntil;
+import com.gemstone.gemfire.test.junit.categories.UnitTest;
+import com.gemstone.gemfire.test.junit.rules.IgnoreUntilRule;
+
+/**
+ * Unit tests for IgnoreUntil JUnit Rule
+ *
+ * @author Kirk Lund
+ */
+@Category(UnitTest.class)
+public class IgnoreUntilRuleTest {
+
+ private static final String ASSERTION_ERROR_MESSAGE = "failing test";
+
+ @Test
+ public void shouldIgnoreWhenUntilIsInFuture() {
+ Result result = runTest(ShouldIgnoreWhenUntilIsInFuture.class);
+
+ assertThat(result.wasSuccessful()).isTrue();
+ assertThat(ShouldIgnoreWhenUntilIsInFuture.count).isEqualTo(0);
+ }
+
+ @Test
+ public void shouldExecuteWhenUntilIsInPast() {
+ Result result = runTest(ShouldExecuteWhenUntilIsInPast.class);
+
+ assertThat(result.wasSuccessful()).isFalse();
+
+ List failures = result.getFailures();
+ assertThat(failures.size()).as("Failures: " + failures).isEqualTo(1);
+
+ Failure failure = failures.get(0);
+ assertThat(failure.getException()).isExactlyInstanceOf(AssertionError.class).hasMessage(ASSERTION_ERROR_MESSAGE);
+ assertThat(ShouldExecuteWhenUntilIsInPast.count).isEqualTo(1);
+ }
+
+ @Test
+ public void shouldExecuteWhenUntilIsDefault() {
+ Result result = runTest(ShouldExecuteWhenUntilIsDefault.class);
+
+ assertThat(result.wasSuccessful()).isFalse();
+
+ List failures = result.getFailures();
+ assertThat(failures.size()).as("Failures: " + failures).isEqualTo(1);
+
+ Failure failure = failures.get(0);
+ assertThat(failure.getException()).isExactlyInstanceOf(AssertionError.class).hasMessage(ASSERTION_ERROR_MESSAGE);
+ assertThat(ShouldExecuteWhenUntilIsDefault.count).isEqualTo(1);
+ }
+
+ public static class ShouldIgnoreWhenUntilIsInFuture {
+ private static int count;
+
+ @Rule
+ public final IgnoreUntilRule ignoreUntilRule = new IgnoreUntilRule();
+
+ @Test
+ @IgnoreUntil(value = "description", until = "3000-01-01")
+ public void doTest() throws Exception {
+ count++;
+ fail(ASSERTION_ERROR_MESSAGE);
+ }
+ }
+
+ public static class ShouldExecuteWhenUntilIsInPast {
+ private static int count;
+
+ @Rule
+ public final IgnoreUntilRule ignoreUntilRule = new IgnoreUntilRule();
+
+ @Test
+ @IgnoreUntil(value = "description", until = "1980-01-01")
+ public void doTest() throws Exception {
+ count++;
+ fail(ASSERTION_ERROR_MESSAGE);
+ }
+ }
+
+ public static class ShouldExecuteWhenUntilIsDefault {
+ private static int count;
+
+ @Rule
+ public final IgnoreUntilRule ignoreUntilRule = new IgnoreUntilRule();
+
+ @Test
+ @IgnoreUntil(value = "description")
+ public void doTest() throws Exception {
+ count++;
+ fail(ASSERTION_ERROR_MESSAGE);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/1be4f932/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/JUnitRuleTestSuite.java
----------------------------------------------------------------------
diff --git a/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/JUnitRuleTestSuite.java b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/JUnitRuleTestSuite.java
new file mode 100755
index 0000000..4c9e315
--- /dev/null
+++ b/gemfire-junit/src/test/java/com/gemstone/gemfire/test/junit/rules/tests/JUnitRuleTestSuite.java
@@ -0,0 +1,33 @@
+/*
+ * 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 com.gemstone.gemfire.test.junit.rules.tests;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+@RunWith(Suite.class)
+@Suite.SuiteClasses({
+ ExpectedTimeoutRuleTest.class,
+ IgnoreUntilRuleTest.class,
+ RepeatRuleTest.class,
+ RetryRuleGlobalWithErrorTest.class,
+ RetryRuleGlobalWithExceptionTest.class,
+ RetryRuleLocalWithErrorTest.class,
+ RetryRuleLocalWithExceptionTest.class,
+})
+public class JUnitRuleTestSuite {
+}