All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.junit.jupiter.engine.extension.TimeoutInvocation Maven / Gradle / Ivy

/*
 * Copyright 2015-2020 the original author or authors.
 *
 * All rights reserved. This program and the accompanying materials are
 * made available under the terms of the Eclipse Public License v2.0 which
 * accompanies this distribution and is available at
 *
 * https://www.eclipse.org/legal/epl-v20.html
 */

package org.junit.jupiter.engine.extension;

import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeoutException;
import java.util.function.Supplier;

import org.junit.jupiter.api.extension.InvocationInterceptor.Invocation;
import org.junit.platform.commons.util.UnrecoverableExceptions;

/**
 * @since 5.5
 */
class TimeoutInvocation implements Invocation {

	private final Invocation delegate;
	private final TimeoutDuration timeout;
	private final ScheduledExecutorService executor;
	private final Supplier descriptionSupplier;

	TimeoutInvocation(Invocation delegate, TimeoutDuration timeout, ScheduledExecutorService executor,
			Supplier descriptionSupplier) {
		this.delegate = delegate;
		this.timeout = timeout;
		this.executor = executor;
		this.descriptionSupplier = descriptionSupplier;
	}

	@Override
	public T proceed() throws Throwable {
		InterruptTask interruptTask = new InterruptTask(Thread.currentThread());
		ScheduledFuture future = executor.schedule(interruptTask, timeout.getValue(), timeout.getUnit());
		Throwable failure = null;
		T result = null;
		try {
			result = delegate.proceed();
		}
		catch (Throwable t) {
			UnrecoverableExceptions.rethrowIfUnrecoverable(t);
			failure = t;
		}
		finally {
			boolean cancelled = future.cancel(false);
			if (!cancelled) {
				future.get();
			}
			if (interruptTask.executed) {
				Thread.interrupted();
				failure = createTimeoutException(failure);
			}
		}
		if (failure != null) {
			throw failure;
		}
		return result;
	}

	private TimeoutException createTimeoutException(Throwable failure) {
		String message = String.format("%s timed out after %s", descriptionSupplier.get(), timeout);
		TimeoutException timeoutError = new TimeoutException(message);
		if (failure != null) {
			timeoutError.addSuppressed(failure);
		}
		return timeoutError;
	}

	static class InterruptTask implements Runnable {

		private final Thread thread;
		private volatile boolean executed;

		InterruptTask(Thread thread) {
			this.thread = thread;
		}

		@Override
		public void run() {
			executed = true;
			thread.interrupt();
		}

	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy