org.springframework.amqp.rabbit.test.RepeatProcessor.java Source code

Java tutorial

Introduction

Here is the source code for org.springframework.amqp.rabbit.test.RepeatProcessor.java

Source

/*
 * Copyright 2002-2010 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 org.springframework.amqp.rabbit.test;

import static org.junit.Assert.assertTrue;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hamcrest.CoreMatchers;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.internal.runners.statements.RunAfters;
import org.junit.internal.runners.statements.RunBefores;
import org.junit.rules.MethodRule;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.Statement;
import org.junit.runners.model.TestClass;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.test.annotation.Repeat;

/**
 * A JUnit method @Rule that looks at Spring repeat annotations on methods and executes the test multiple times
 * (without re-initializing the test case if necessary). To avoid re-initializing use the {@link #isInitialized()}
 * method to protect the @Before and @After methods.
 *
 * @author Dave Syer
 * @since 2.0
 *
 */
public class RepeatProcessor implements MethodRule {

    private static final Log logger = LogFactory.getLog(RepeatProcessor.class);

    private final int concurrency;

    private volatile boolean initialized = false;

    private volatile boolean finalizing = false;

    public RepeatProcessor() {
        this(0);
    }

    public RepeatProcessor(int concurrency) {
        this.concurrency = concurrency < 0 ? 0 : concurrency;
    }

    public Statement apply(final Statement base, FrameworkMethod method, final Object target) {

        Repeat repeat = AnnotationUtils.findAnnotation(method.getMethod(), Repeat.class);
        if (repeat == null) {
            return base;
        }

        final int repeats = repeat.value();
        if (repeats <= 1) {
            return base;
        }

        initializeIfNecessary(target);

        if (concurrency <= 0) {
            return new Statement() {
                @Override
                public void evaluate() throws Throwable {
                    try {
                        for (int i = 0; i < repeats; i++) {
                            try {
                                base.evaluate();
                            } catch (Throwable t) {
                                throw new IllegalStateException(
                                        "Failed on iteration: " + i + " of " + repeats + " (started at 0)", t);
                            }
                        }
                    } finally {
                        finalizeIfNecessary(target);
                    }
                }
            };
        }
        return new Statement() {
            @Override
            public void evaluate() throws Throwable {
                List<Future<Boolean>> results = new ArrayList<Future<Boolean>>();
                ExecutorService executor = Executors.newFixedThreadPool(concurrency);
                CompletionService<Boolean> completionService = new ExecutorCompletionService<Boolean>(executor);
                try {
                    for (int i = 0; i < repeats; i++) {
                        final int count = i;
                        results.add(completionService.submit(new Callable<Boolean>() {
                            public Boolean call() {
                                try {
                                    base.evaluate();
                                } catch (Throwable t) {
                                    throw new IllegalStateException("Failed on iteration: " + count, t);
                                }
                                return true;
                            }
                        }));
                    }
                    for (int i = 0; i < repeats; i++) {
                        Future<Boolean> future = completionService.take();
                        assertTrue("Null result from completer", future.get());
                    }
                } finally {
                    executor.shutdownNow();
                    finalizeIfNecessary(target);
                }
            }
        };
    }

    private void finalizeIfNecessary(Object target) {
        finalizing = true;
        List<FrameworkMethod> afters = new TestClass(target.getClass()).getAnnotatedMethods(After.class);
        try {
            if (!afters.isEmpty()) {
                logger.debug("Running @After methods");
                try {
                    new RunAfters(new Statement() {
                        public void evaluate() {
                        }
                    }, afters, target).evaluate();
                } catch (Throwable e) {
                    Assert.assertThat(e, CoreMatchers.not(CoreMatchers.anything()));
                }
            }
        } finally {
            finalizing = false;
        }
    }

    private void initializeIfNecessary(Object target) {
        TestClass testClass = new TestClass(target.getClass());
        List<FrameworkMethod> befores = testClass.getAnnotatedMethods(Before.class);
        if (!befores.isEmpty()) {
            logger.debug("Running @Before methods");
            try {
                new RunBefores(new Statement() {
                    public void evaluate() {
                    }
                }, befores, target).evaluate();
            } catch (Throwable e) {
                Assert.assertThat(e, CoreMatchers.not(CoreMatchers.anything()));
            }
            initialized = true;
        }
        if (!testClass.getAnnotatedMethods(After.class).isEmpty()) {
            initialized = true;
        }
    }

    public boolean isInitialized() {
        return initialized;
    }

    public boolean isFinalizing() {
        return finalizing;
    }

    public int getConcurrency() {
        return concurrency > 0 ? concurrency : 1;
    }
}