/*
* 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 org.apache.harmony.tests.java.lang;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.Map;
public class ThreadTest extends junit.framework.TestCase {
static class SimpleThread implements Runnable {
int delay;
public void run() {
try {
synchronized (this) {
this.notify();
this.wait(delay);
}
} catch (InterruptedException e) {
return;
}
}
public SimpleThread(int d) {
if (d >= 0)
delay = d;
}
}
static class YieldThread implements Runnable {
volatile int delay;
public void run() {
int x = 0;
while (true) {
++x;
}
}
public YieldThread(int d) {
if (d >= 0)
delay = d;
}
}
static class ResSupThread implements Runnable {
Thread parent;
volatile int checkVal = -1;
public void run() {
try {
synchronized (this) {
this.notify();
}
while (true) {
checkVal++;
zz();
Thread.sleep(100);
}
} catch (InterruptedException e) {
return;
} catch (BogusException e) {
try {
// Give parent a chance to sleep
Thread.sleep(500);
} catch (InterruptedException x) {
}
parent.interrupt();
while (!Thread.currentThread().isInterrupted()) {
// Don't hog the CPU
try {
Thread.sleep(50);
} catch (InterruptedException x) {
// This is what we've been waiting for...don't throw it
// away!
break;
}
}
}
}
public void zz() throws BogusException {
}
public ResSupThread(Thread t) {
parent = t;
}
public synchronized int getCheckVal() {
return checkVal;
}
}
static class BogusException extends Throwable {
private static final long serialVersionUID = 1L;
public BogusException(String s) {
super(s);
}
}
Thread st, ct, spinner;
/**
* java.lang.Thread#Thread(java.lang.Runnable)
*/
public void test_ConstructorLjava_lang_Runnable() {
// Test for method java.lang.Thread(java.lang.Runnable)
ct = new Thread(new SimpleThread(10));
ct.start();
}
/**
* java.lang.Thread#Thread(java.lang.Runnable, java.lang.String)
*/
public void test_ConstructorLjava_lang_RunnableLjava_lang_String() {
// Test for method java.lang.Thread(java.lang.Runnable,
// java.lang.String)
Thread st1 = new Thread(new SimpleThread(1), "SimpleThread1");
assertEquals("Constructed thread with incorrect thread name", "SimpleThread1", st1
.getName());
st1.start();
}
/**
* java.lang.Thread#Thread(java.lang.String)
*/
public void test_ConstructorLjava_lang_String() {
// Test for method java.lang.Thread(java.lang.String)
Thread t = new Thread("Testing");
assertEquals("Created tread with incorrect name",
"Testing", t.getName());
t.start();
}
/**
* java.lang.Thread#Thread(java.lang.ThreadGroup, java.lang.Runnable)
*/
public void test_ConstructorLjava_lang_ThreadGroupLjava_lang_Runnable() {
// Test for method java.lang.Thread(java.lang.ThreadGroup,
// java.lang.Runnable)
ThreadGroup tg = new ThreadGroup("Test Group1");
st = new Thread(tg, new SimpleThread(1), "SimpleThread2");
assertTrue("Returned incorrect thread group", st.getThreadGroup() == tg);
st.start();
try {
st.join();
} catch (InterruptedException e) {
}
tg.destroy();
}
/**
* java.lang.Thread#Thread(java.lang.ThreadGroup, java.lang.Runnable,
*java.lang.String)
*/
public void test_ConstructorLjava_lang_ThreadGroupLjava_lang_RunnableLjava_lang_String() {
// Test for method java.lang.Thread(java.lang.ThreadGroup,
// java.lang.Runnable, java.lang.String)
ThreadGroup tg = new ThreadGroup("Test Group2");
st = new Thread(tg, new SimpleThread(1), "SimpleThread3");
assertTrue("Constructed incorrect thread", (st.getThreadGroup() == tg)
&& st.getName().equals("SimpleThread3"));
st.start();
try {
st.join();
} catch (InterruptedException e) {
}
tg.destroy();
Runnable r = new Runnable() {
public void run() {
}
};
ThreadGroup foo = null;
try {
new Thread(foo = new ThreadGroup("foo"), r, null);
// Should not get here
fail("Null cannot be accepted as Thread name");
} catch (NullPointerException npe) {
assertTrue("Null cannot be accepted as Thread name", true);
foo.destroy();
}
}
/**
* java.lang.Thread#Thread(java.lang.ThreadGroup, java.lang.String)
*/
public void test_ConstructorLjava_lang_ThreadGroupLjava_lang_String() {
// Test for method java.lang.Thread(java.lang.ThreadGroup,
// java.lang.String)
st = new Thread(new SimpleThread(1), "SimpleThread4");
assertEquals("Returned incorrect thread name",
"SimpleThread4", st.getName());
st.start();
}
/**
* java.lang.Thread#activeCount()
*/
public void test_activeCount() {
// Test for method int java.lang.Thread.activeCount()
Thread t = new Thread(new SimpleThread(10));
int active = 0;
synchronized (t) {
t.start();
active = Thread.activeCount();
}
assertTrue("Incorrect activeCount for current group: " + active, active > 1);
try {
t.join();
} catch (InterruptedException e) {
}
}
/**
* java.lang.Thread#checkAccess()
*/
public void test_checkAccess() {
// Test for method void java.lang.Thread.checkAccess()
ThreadGroup tg = new ThreadGroup("Test Group3");
try {
st = new Thread(tg, new SimpleThread(1), "SimpleThread5");
st.checkAccess();
assertTrue("CheckAccess passed", true);
} catch (SecurityException e) {
fail("CheckAccess failed : " + e.getMessage());
}
st.start();
try {
st.join();
} catch (InterruptedException e) {
}
tg.destroy();
}
/**
* java.lang.Thread#countStackFrames()
*/
@SuppressWarnings("deprecation")
public void test_countStackFrames() {
/*
* Thread.countStackFrames() is unpredictable, so we just test that it
* doesn't throw an exception.
*/
Thread.currentThread().countStackFrames();
}
/**
* java.lang.Thread#currentThread()
*/
public void test_currentThread() {
assertNotNull(Thread.currentThread());
}
public void test_destroy_throwsUnsupportedOperationException() {
try {
new Thread().destroy();
fail();
} catch (UnsupportedOperationException expected) {
}
}
/**
* java.lang.Thread#enumerate(java.lang.Thread[])
*/
public void test_enumerate$Ljava_lang_Thread() {
// Test for method int java.lang.Thread.enumerate(java.lang.Thread [])
// The test has been updated according to HARMONY-1974 JIRA issue.
class MyThread extends Thread {
MyThread(ThreadGroup tg, String name) {
super(tg, name);
}
boolean failed = false;
String failMessage = null;
public void run() {
SimpleThread st1 = null;
SimpleThread st2 = null;
ThreadGroup mytg = null;
Thread firstOne = null;
Thread secondOne = null;
try {
int arrayLength = 10;
Thread[] tarray = new Thread[arrayLength];
st1 = new SimpleThread(-1);
st2 = new SimpleThread(-1);
mytg = new ThreadGroup("jp");
firstOne = new Thread(mytg, st1, "firstOne2");
secondOne = new Thread(mytg, st2, "secondOne1");
int count = Thread.enumerate(tarray);
assertEquals("Incorrect value returned1",
1, count);
synchronized (st1) {
firstOne.start();
try {
st1.wait();
} catch (InterruptedException e) {
}
}
count = Thread.enumerate(tarray);
assertEquals("Incorrect value returned2",
2, count);
synchronized (st2) {
secondOne.start();
try {
st2.wait();
} catch (InterruptedException e) {
}
}
count = Thread.enumerate(tarray);
assertEquals("Incorrect value returned3",
3, count);
} catch (junit.framework.AssertionFailedError e) {
failed = true;
failMessage = e.getMessage();
} finally {
synchronized (st1) {
firstOne.interrupt();
}
synchronized (st2) {
secondOne.interrupt();
}
try {
firstOne.join();
secondOne.join();
} catch (InterruptedException e) {
}
mytg.destroy();
}
}
}
;
ThreadGroup tg = new ThreadGroup("tg");
MyThread t = new MyThread(tg, "top");
t.start();
try {
t.join();
} catch (InterruptedException e) {
fail("Unexpected interrupt");
} finally {
tg.destroy();
}
assertFalse(t.failMessage, t.failed);
}
/**
* java.lang.Thread#getContextClassLoader()
*/
public void test_getContextClassLoader() {
// Test for method java.lang.ClassLoader
// java.lang.Thread.getContextClassLoader()
Thread t = new Thread();
assertTrue("Incorrect class loader returned",
t.getContextClassLoader() == Thread.currentThread()
.getContextClassLoader());
t.start();
}
/**
* java.lang.Thread#getName()
*/
public void test_getName() {
// Test for method java.lang.String java.lang.Thread.getName()
st = new Thread(new SimpleThread(1), "SimpleThread6");
assertEquals("Returned incorrect thread name",
"SimpleThread6", st.getName());
st.start();
}
/**
* java.lang.Thread#getPriority()
*/
public void test_getPriority() {
// Test for method int java.lang.Thread.getPriority()
st = new Thread(new SimpleThread(1));
st.setPriority(Thread.MAX_PRIORITY);
assertTrue("Returned incorrect thread priority",
st.getPriority() == Thread.MAX_PRIORITY);
st.start();
}
/**
* java.lang.Thread#getThreadGroup()
*/
public void test_getThreadGroup() {
// Test for method java.lang.ThreadGroup
// java.lang.Thread.getThreadGroup()
ThreadGroup tg = new ThreadGroup("Test Group4");
st = new Thread(tg, new SimpleThread(1), "SimpleThread8");
assertTrue("Returned incorrect thread group", st.getThreadGroup() == tg);
st.start();
try {
st.join();
} catch (InterruptedException e) {
}
assertNull("group should be null", st.getThreadGroup());
assertNotNull("toString() should not be null", st.toString());
tg.destroy();
final Object lock = new Object();
Thread t = new Thread() {
@Override
public void run() {
synchronized (lock) {
lock.notifyAll();
}
}
};
synchronized (lock) {
t.start();
try {
lock.wait();
} catch (InterruptedException e) {
}
}
int running = 0;
while (t.isAlive())
running++;
ThreadGroup group = t.getThreadGroup();
assertNull("ThreadGroup is not null", group);
}
/**
* java.lang.Thread#interrupt()
*/
public void test_interrupt() {
// Test for method void java.lang.Thread.interrupt()
final Object lock = new Object();
class ChildThread1 extends Thread {
Thread parent;
boolean sync;
@Override
public void run() {
if (sync) {
synchronized (lock) {
lock.notify();
try {
lock.wait();
} catch (InterruptedException e) {
}
}
}
parent.interrupt();
}
public ChildThread1(Thread p, String name, boolean sync) {
super(name);
parent = p;
this.sync = sync;
}
}
boolean interrupted = false;
try {
ct = new ChildThread1(Thread.currentThread(), "Interrupt Test1",
false);
synchronized (lock) {
ct.start();
lock.wait();
}
} catch (InterruptedException e) {
interrupted = true;
}
assertTrue("Failed to Interrupt thread1", interrupted);
interrupted = false;
try {
ct = new ChildThread1(Thread.currentThread(), "Interrupt Test2",
true);
synchronized (lock) {
ct.start();
lock.wait();
lock.notify();
}
Thread.sleep(20000);
} catch (InterruptedException e) {
interrupted = true;
}
assertTrue("Failed to Interrupt thread2", interrupted);
}
/**
* java.lang.Thread#interrupted()
*/
public void test_interrupted() {
assertFalse("Interrupted returned true for non-interrupted thread", Thread
.interrupted());
Thread.currentThread().interrupt();
assertTrue("Interrupted returned true for non-interrupted thread", Thread.interrupted());
assertFalse("Failed to clear interrupted flag", Thread.interrupted());
}
/**
* java.lang.Thread#isAlive()
*/
public void test_isAlive() {
// Test for method boolean java.lang.Thread.isAlive()
SimpleThread simple;
st = new Thread(simple = new SimpleThread(500));
assertFalse("A thread that wasn't started is alive.", st.isAlive());
synchronized (simple) {
st.start();
try {
simple.wait();
} catch (InterruptedException e) {
}
}
assertTrue("Started thread returned false", st.isAlive());
try {
st.join();
} catch (InterruptedException e) {
fail("Thread did not die");
}
assertTrue("Stopped thread returned true", !st.isAlive());
}
/**
* java.lang.Thread#isDaemon()
*/
public void test_isDaemon() {
// Test for method boolean java.lang.Thread.isDaemon()
st = new Thread(new SimpleThread(1), "SimpleThread10");
assertTrue("Non-Daemon thread returned true", !st.isDaemon());
st.setDaemon(true);
assertTrue("Daemon thread returned false", st.isDaemon());
st.start();
}
/**
* java.lang.Thread#isInterrupted()
*/
public void test_isInterrupted() {
// Test for method boolean java.lang.Thread.isInterrupted()
class SpinThread implements Runnable {
public volatile boolean done = false;
public void run() {
while (!Thread.currentThread().isInterrupted())
;
while (!done)
;
}
}
SpinThread spin = new SpinThread();
spinner = new Thread(spin);
spinner.start();
Thread.yield();
try {
assertTrue("Non-Interrupted thread returned true", !spinner
.isInterrupted());
spinner.interrupt();
assertTrue("Interrupted thread returned false", spinner
.isInterrupted());
spin.done = true;
} finally {
spinner.interrupt();
spin.done = true;
}
}
/**
* java.lang.Thread#join()
*/
public void test_join() {
// Test for method void java.lang.Thread.join()
SimpleThread simple;
try {
st = new Thread(simple = new SimpleThread(100));
// cause isAlive() to be compiled by the JIT, as it must be called
// within 100ms below.
assertTrue("Thread is alive", !st.isAlive());
synchronized (simple) {
st.start();
simple.wait();
}
st.join();
} catch (InterruptedException e) {
fail("Join failed ");
}
assertTrue("Joined thread is still alive", !st.isAlive());
boolean result = true;
Thread th = new Thread("test");
try {
th.join();
} catch (InterruptedException e) {
result = false;
}
assertTrue("Hung joining a non-started thread", result);
th.start();
}
/**
* java.lang.Thread#join(long)
*/
public void test_joinJ() {
// Test for method void java.lang.Thread.join(long)
SimpleThread simple;
try {
st = new Thread(simple = new SimpleThread(1000), "SimpleThread12");
// cause isAlive() to be compiled by the JIT, as it must be called
// within 100ms below.
assertTrue("Thread is alive", !st.isAlive());
synchronized (simple) {
st.start();
simple.wait();
}
st.join(10);
} catch (InterruptedException e) {
fail("Join failed ");
}
assertTrue("Join failed to timeout", st.isAlive());
st.interrupt();
try {
st = new Thread(simple = new SimpleThread(100), "SimpleThread13");
synchronized (simple) {
st.start();
simple.wait();
}
st.join(1000);
} catch (InterruptedException e) {
fail("Join failed : " + e.getMessage());
return;
}
assertTrue("Joined thread is still alive", !st.isAlive());
final Object lock = new Object();
final Thread main = Thread.currentThread();
Thread killer = new Thread(new Runnable() {
public void run() {
try {
synchronized (lock) {
lock.notify();
}
Thread.sleep(100);
} catch (InterruptedException e) {
return;
}
main.interrupt();
}
});
boolean result = true;
Thread th = new Thread("test");
try {
synchronized (lock) {
killer.start();
lock.wait();
}
th.join(200);
} catch (InterruptedException e) {
result = false;
}
killer.interrupt();
assertTrue("Hung joining a non-started thread", result);
th.start();
}
/**
* java.lang.Thread#join(long, int)
*/
public void test_joinJI() throws Exception {
// Test for method void java.lang.Thread.join(long, int)
SimpleThread simple;
st = new Thread(simple = new SimpleThread(1000), "Squawk1");
assertTrue("Thread is alive", !st.isAlive());
synchronized (simple) {
st.start();
simple.wait();
}
long firstRead = System.currentTimeMillis();
st.join(100, 999999);
long secondRead = System.currentTimeMillis();
assertTrue("Did not join by appropriate time: " + secondRead + "-"
+ firstRead + "=" + (secondRead - firstRead), secondRead
- firstRead <= 300);
assertTrue("Joined thread is not alive", st.isAlive());
st.interrupt();
final Object lock = new Object();
final Thread main = Thread.currentThread();
Thread killer = new Thread(new Runnable() {
public void run() {
try {
synchronized (lock) {
lock.notify();
}
Thread.sleep(100);
} catch (InterruptedException e) {
return;
}
main.interrupt();
}
});
boolean result = true;
Thread th = new Thread("test");
try {
synchronized (lock) {
killer.start();
lock.wait();
}
th.join(200, 20);
} catch (InterruptedException e) {
result = false;
}
killer.interrupt();
assertTrue("Hung joining a non-started thread", result);
th.start();
}
/**
* java.lang.Thread#run()
*/
public void test_run() {
// Test for method void java.lang.Thread.run()
class RunThread implements Runnable {
boolean didThreadRun = false;
public void run() {
didThreadRun = true;
}
}
RunThread rt = new RunThread();
Thread t = new Thread(rt);
try {
t.start();
int count = 0;
while (!rt.didThreadRun && count < 20) {
Thread.sleep(100);
count++;
}
assertTrue("Thread did not run", rt.didThreadRun);
t.join();
} catch (InterruptedException e) {
assertTrue("Joined thread was interrupted", true);
}
assertTrue("Joined thread is still alive", !t.isAlive());
}
/**
* java.lang.Thread#setDaemon(boolean)
*/
public void test_setDaemonZ() {
// Test for method void java.lang.Thread.setDaemon(boolean)
st = new Thread(new SimpleThread(1), "SimpleThread14");
st.setDaemon(true);
assertTrue("Failed to set thread as daemon thread", st.isDaemon());
st.start();
}
/**
* java.lang.Thread#setName(java.lang.String)
*/
public void test_setNameLjava_lang_String() {
// Test for method void java.lang.Thread.setName(java.lang.String)
st = new Thread(new SimpleThread(1), "SimpleThread15");
st.setName("Bogus Name");
assertEquals("Failed to set thread name",
"Bogus Name", st.getName());
try {
st.setName(null);
fail("Null should not be accepted as a valid name");
} catch (NullPointerException e) {
// success
assertTrue("Null should not be accepted as a valid name", true);
}
st.start();
}
/**
* java.lang.Thread#setPriority(int)
*/
public void test_setPriorityI() {
// Test for method void java.lang.Thread.setPriority(int)
st = new Thread(new SimpleThread(1));
st.setPriority(Thread.MAX_PRIORITY);
assertTrue("Failed to set priority",
st.getPriority() == Thread.MAX_PRIORITY);
st.start();
}
/**
* java.lang.Thread#sleep(long)
*/
public void test_sleepJ() {
// Test for method void java.lang.Thread.sleep(long)
// TODO : Test needs enhancing.
long stime = 0, ftime = 0;
try {
stime = System.currentTimeMillis();
Thread.sleep(1000);
ftime = System.currentTimeMillis();
} catch (InterruptedException e) {
fail("Unexpected interrupt received");
}
assertTrue("Failed to sleep long enough", (ftime - stime) >= 800);
}
/**
* java.lang.Thread#sleep(long, int)
*/
public void test_sleepJI() {
// Test for method void java.lang.Thread.sleep(long, int)
// TODO : Test needs revisiting.
long stime = 0, ftime = 0;
try {
stime = System.currentTimeMillis();
Thread.sleep(1000, 999999);
ftime = System.currentTimeMillis();
} catch (InterruptedException e) {
fail("Unexpected interrupt received");
}
long result = ftime - stime;
assertTrue("Failed to sleep long enough: " + result, result >= 900
&& result <= 1100);
}
/**
* java.lang.Thread#start()
*/
public void test_start() {
// Test for method void java.lang.Thread.start()
try {
ResSupThread t = new ResSupThread(Thread.currentThread());
synchronized (t) {
ct = new Thread(t, "Interrupt Test4");
ct.start();
t.wait();
}
assertTrue("Thread is not running1", ct.isAlive());
// Let the child thread get going.
int orgval = t.getCheckVal();
Thread.sleep(150);
assertTrue("Thread is not running2", orgval != t.getCheckVal());
ct.interrupt();
} catch (InterruptedException e) {
fail("Unexpected interrupt occurred");
}
}
/**
* java.lang.Thread#toString()
*/
public void test_toString() {
// Test for method java.lang.String java.lang.Thread.toString()
ThreadGroup tg = new ThreadGroup("Test Group5");
st = new Thread(tg, new SimpleThread(1), "SimpleThread17");
final String stString = st.toString();
final String expected = "Thread[SimpleThread17,5,Test Group5]";
assertTrue("Returned incorrect string: " + stString + "\t(expecting :"
+ expected + ")", stString.equals(expected));
st.start();
try {
st.join();
} catch (InterruptedException e) {
}
tg.destroy();
}
/**
* java.lang.Thread#getAllStackTraces()
*/
public void test_getAllStackTraces() {
Map<Thread, StackTraceElement[]> stMap = Thread.getAllStackTraces();
assertNotNull(stMap);
//TODO add security-based tests
}
/**
* java.lang.Thread#getDefaultUncaughtExceptionHandler
* java.lang.Thread#setDefaultUncaughtExceptionHandler
*/
public void test_get_setDefaultUncaughtExceptionHandler() {
class Handler implements UncaughtExceptionHandler {
public void uncaughtException(Thread thread, Throwable ex) {
}
}
final Handler handler = new Handler();
Thread.setDefaultUncaughtExceptionHandler(handler);
assertSame(handler, Thread.getDefaultUncaughtExceptionHandler());
Thread.setDefaultUncaughtExceptionHandler(null);
assertNull(Thread.getDefaultUncaughtExceptionHandler());
//TODO add security-based tests
}
/**
* java.lang.Thread#getStackTrace()
*/
public void test_getStackTrace() {
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
assertNotNull(stackTrace);
stack_trace_loop:
{
for (int i = 0; i < stackTrace.length; i++) {
StackTraceElement e = stackTrace[i];
if (getClass().getName().equals(e.getClassName())) {
if ("test_getStackTrace".equals(e.getMethodName())) {
break stack_trace_loop;
}
}
}
fail("class and method not found in stack trace");
}
//TODO add security-based tests
}
/**
* java.lang.Thread#getState()
*/
public void test_getState() {
Thread.State state = Thread.currentThread().getState();
assertNotNull(state);
assertEquals(Thread.State.RUNNABLE, state);
//TODO add additional state tests
}
/**
* java.lang.Thread#getUncaughtExceptionHandler
* java.lang.Thread#setUncaughtExceptionHandler
*/
public void test_get_setUncaughtExceptionHandler() {
class Handler implements UncaughtExceptionHandler {
public void uncaughtException(Thread thread, Throwable ex) {
}
}
final Handler handler = new Handler();
Thread.currentThread().setUncaughtExceptionHandler(handler);
assertSame(handler, Thread.currentThread().getUncaughtExceptionHandler());
Thread.currentThread().setUncaughtExceptionHandler(null);
//TODO add security-based tests
}
/**
* java.lang.Thread#getId()
*/
public void test_getId() {
assertTrue("current thread's ID is not positive", Thread.currentThread().getId() > 0);
//check all the current threads for positive IDs
Map<Thread, StackTraceElement[]> stMap = Thread.getAllStackTraces();
for (Thread thread : stMap.keySet()) {
assertTrue("thread's ID is not positive: " + thread.getName(), thread.getId() > 0);
}
}
@Override
protected void tearDown() {
try {
if (st != null)
st.interrupt();
} catch (Exception e) {
}
try {
if (spinner != null)
spinner.interrupt();
} catch (Exception e) {
}
try {
if (ct != null)
ct.interrupt();
} catch (Exception e) {
}
try {
spinner = null;
st = null;
ct = null;
System.runFinalization();
} catch (Exception e) {
}
}
}