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

ee.jakarta.tck.concurrent.framework.TestUtil Maven / Gradle / Ivy

/*
 * Copyright (c) 2022 Contributors to the Eclipse Foundation
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0, which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception, which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 */

package ee.jakarta.tck.concurrent.framework;

import static org.testng.Assert.fail;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.Enumeration;
import java.util.Properties;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import ee.jakarta.tck.concurrent.common.managedTaskListener.ListenerEvent;
import ee.jakarta.tck.concurrent.common.managedTaskListener.ManagedTaskListenerImpl;
import jakarta.enterprise.concurrent.ContextService;
import jakarta.enterprise.concurrent.ManagedExecutorService;
import jakarta.enterprise.concurrent.ManagedScheduledExecutorService;
import jakarta.enterprise.concurrent.ManagedThreadFactory;

/**
 * Utility methods to be used on the client or server side. 
 * These utilities can be broken up into distinct categorities: 
 * - HTTP utilities
 * - Context lookup utilities
 * - Waiter utilities
 * - Assertions
 */
public final class TestUtil {
	public static final TestLogger log = TestLogger.get(TestUtil.class);

	public static final String nl = System.lineSeparator();
	
	// ########## HTTP ##########

	/**
	 * HTTP convenience method for servlets to get a response from another servlet. 
	 * Test clients should extend the {@link TestClient} class that has its own HTTP methods.
	 * 
	 * @param connection - the URLConnection
	 * @return String - response body
	 * @throws IOException
	 */
	public static String getResponse(URLConnection con) throws IOException {	
		try (BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()))) {
			
			StringBuffer response = new StringBuffer();
			
			String line;
			while ((line = br.readLine()) != null) {
				response.append(line).append(nl);
			}

			return response.toString();
		}
	}

	/**
	 * HTTP convenience method for servlets to create a URLConnection and post properties 
	 * to that connection. 
	 * 
	 * Test clients should extend the {@link TestClient} class that has its own HTTP methods.
	 * 
	 * @param url - the URL to open a connection to
	 * @param props - the properties to put into the connection input stream
	 * 
	 * @return the connection for further testing
	 * @throws IOException
	 */
	public static URLConnection sendPostData(URL url, Properties props) throws IOException {
		log.info("Opening url connection to: " + url.toString());
		URLConnection urlConn = url.openConnection();
		// Begin POST of properties to SERVLET
		String argString = TestUtil.toEncodedString(props);
		urlConn.setDoOutput(true);
		urlConn.setDoInput(true);
		urlConn.setUseCaches(false);
		DataOutputStream out = new DataOutputStream(urlConn.getOutputStream());
		out.writeBytes(argString);
		out.flush();
		out.close();
		// End POST
		return urlConn;
	}
	
	static String toEncodedString(Properties args) throws UnsupportedEncodingException {
		StringBuffer buf = new StringBuffer();
		Enumeration names = args.propertyNames();
		while (names.hasMoreElements()) {
			String name = (String) names.nextElement();
			String value = args.getProperty(name);
			
			buf.append(URLEncoder.encode(name, StandardCharsets.UTF_8.name()))
				.append("=")
				.append(URLEncoder.encode(value, StandardCharsets.UTF_8.name()));
			
			if (names.hasMoreElements())
				buf.append("&");
		}
		return buf.toString();
	}
	
	//########## Lookups ##########	
	public static  T lookup(String jndiName) {
		Context ctx = null;
		T targetObject = null;
		try {
			ctx = new InitialContext();
			targetObject = (T) ctx.lookup(jndiName);
		} catch (NamingException e) {
			throw new RuntimeException("failed to lookup resource.", e);
		} finally {
			try {
				ctx.close();
			} catch (Exception ignore) {
			}
		}
		return targetObject;
	}
	
	public static ContextService getContextService() {
		return lookup(TestConstants.DefaultContextService);
	}
	
	public static ManagedExecutorService getManagedExecutorService() {
		return lookup(TestConstants.DefaultManagedExecutorService);
	}
	
	public static ManagedScheduledExecutorService getManagedScheduledExecutorService() {
		return lookup(TestConstants.DefaultManagedScheduledExecutorService);
	}
	
	public static ManagedThreadFactory getManagedThreadFactory() {
		return lookup(TestConstants.DefaultManagedThreadFactory);
	}
	
	//########## Waiters ##########
	
	/**
	 * USE WITH CAUTION!! 
	 * When possible tests should use waitFor methods to wait for specific condition to be meet.
	 * Pausing the thread for a specific duration will directly impact test performance but in some cases is required. 
	 * 
	 * Pauses the calling thread for the specified duration
	 * 
	 * @param duration - duration to sleep
	 * @throws InterruptedException 
	 */
	public static void sleep(Duration duration) throws InterruptedException {
		log.config("Sleeping " + duration.toMillis() + " milliseconds");
		Thread.sleep(duration.toMillis());
	}
	
	/**
	 * Waits for task to complete, but will timeout after {@link TestConstants#WaitTimeout}
	 * @param future to wait for
	 * @return result
	 */
	public static  T waitForTaskComplete(final Future future) {
		return waitForTaskComplete(future, TestConstants.WaitTimeout.toMillis());
	}
	
	/**
	 * Waits for task to complete, but will timeout after specified timeout in millis
	 * @param future - the future to wait for
	 * @param maxWaitTimeMillis - the timeout
	 * @return result
	 */
	public static  T waitForTaskComplete(final Future future, final long maxWaitTimeMillis) {
		T result = null;
		try {
			result = future.get(maxWaitTimeMillis, TimeUnit.MILLISECONDS);
		} catch (InterruptedException e) {
			throw new RuntimeException("waitForTaskComplete", e);
		} catch (ExecutionException e) {
			throw new RuntimeException("waitForTaskComplete", e);
		} catch (TimeoutException e) {
			throw new RuntimeException("failed to finish task in " + maxWaitTimeMillis + " milliseconds. ", e);
		} catch (Exception e) { // may caught the exception thrown from the task
								// submitted.
			throw new RuntimeException("waitForTaskComplete failed to finish task", e);
		}
		return result;
	}
	
	/**
	 * Wait for listener to complete, but will timeout after {@link TestConstants#WaitTimeout}, 
	 * and will be polled ever {@link TestConstants#PollInterval}
	 * 
	 * @param managedTaskListener - the listener to be polled
	 */
	public static void waitForListenerComplete(ManagedTaskListenerImpl managedTaskListener) {
		waitForListenerComplete(managedTaskListener, TestConstants.WaitTimeout.toMillis(), TestConstants.PollInterval.toMillis());
	}

	/**
	 * Wait for listener to complete, but will timeout after a specified timeout, 
	 * and will be polled ever specified interval
	 * 
	 * @param managedTaskListener - the listener to be polled
	 * @param maxWaitTimeMillis - timeout
	 * @param pollIntervalMillis - poll interval
	 */
	public static void waitForListenerComplete(ManagedTaskListenerImpl managedTaskListener, long maxWaitTimeMillis,
			long pollIntervalMillis) {
		final long stopTime = System.currentTimeMillis() + maxWaitTimeMillis;
		while (!managedTaskListener.eventCalled(ListenerEvent.DONE) && System.currentTimeMillis() < stopTime) {
			try {
				Thread.sleep(pollIntervalMillis);
			} catch (InterruptedException e) {
				throw new RuntimeException("Thread was inerrupted while sleeping", e);
			}
		}
	}

	/**
	 * Waits for future to complete, but will timeout after {@link TestConstants#WaitTimeout},
	 * and will be polled every {@link TestConstants#PollInterval}
	 * 
	 * The difference between this method and waitForTaskComplete is that some
	 * scheduled task will return values for multiple times, in this situation
	 * waitForTaskComplete does not work.
	 * 
	 * @param future - the future to wait for
	 */
	public static void waitTillFutureIsDone(Future future) {
		long start = System.currentTimeMillis();

		while (!future.isDone()) {
			try {
				Thread.sleep(TestConstants.PollInterval.toMillis());
			} catch (InterruptedException ignore) {
			}

			if ((System.currentTimeMillis() - start) > TestConstants.WaitTimeout.toMillis()) {
				throw new RuntimeException("Future did not finish before wait timeout elapsed.");
			}
		}
	}
	
	/**
	 * Waits for future to throw an error, but will timeout after {@link TestConstants#WaitTimeout},
	 * and will be polled every {@link TestConstants#PollInterval}
	 * 
	 * @param future - the future to wait for
	 */
	public static void waitTillFutureThrowsException(Future future, Class expected) {
		long start = System.currentTimeMillis();

		while (true) {
			try {
				Thread.sleep(TestConstants.PollInterval.toMillis());
				future.get();
			} catch (InterruptedException ignore) {
			} catch (Throwable e) {
				if(e.getClass().equals(expected)) {
					return; //expected
				}
			}

			if ((System.currentTimeMillis() - start) > TestConstants.WaitTimeout.toMillis()) {
				throw new RuntimeException("Future did not throw exception before wait timeout elapased.");
			}
		}
	}
	
	/**
	 * Waits until thread is finished, but will timeout after {@link TestConstants#WaitTimeout},
	 * and will be polled every {@link TestConstants#PollInterval}
	 * 
	 * @param thread - the thread to wait for
	 */
	public static void waitTillThreadFinish(Thread thread) {
		long start = System.currentTimeMillis();

		while (thread.isAlive()) {
			try {
				Thread.sleep(TestConstants.PollInterval.toMillis());
			} catch (InterruptedException ignore) {
			}

			if ((System.currentTimeMillis() - start) > TestConstants.WaitTimeout.toMillis()) {
				throw new RuntimeException("Thread did not finish before wait timeout elapsed.");
			}
		}
	}
	
	//########## Custom assertions ##########

	public static void assertInRange(Object[] range, Object actual) {
		String expected = "";
		for (Object each : range) {
			expected += each.toString();
			expected += ",";
		}
		expected = expected.substring(0, expected.length() - 1);
		String msg = "expected in " + expected + " but you got " + actual;
		for (Object each : range) {
			if (each.equals(actual)) {
				return;
			}
		}
		fail(msg);
	}

	public static void assertIntInRange(int low, int high, int actual) {
		String msg = "expected in range " + low + " , " + high;
		msg += " but you got " + actual;
		if (actual < low || actual > high) {
			fail(msg);
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy