1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package libcore.java.lang;
18
19import java.util.concurrent.atomic.AtomicInteger;
20import junit.framework.Assert;
21import junit.framework.TestCase;
22import libcore.java.lang.ref.FinalizationTester;
23
24public final class ThreadTest extends TestCase {
25    static {
26        System.loadLibrary("javacoretests");
27    }
28
29    /**
30     * getContextClassLoader returned a non-application class loader.
31     * http://code.google.com/p/android/issues/detail?id=5697
32     */
33    public void testJavaContextClassLoader() throws Exception {
34        Assert.assertNotNull("Must have a Java context ClassLoader",
35                Thread.currentThread().getContextClassLoader());
36    }
37
38    public void testLeakingStartedThreads() {
39        final AtomicInteger finalizedThreadsCount = new AtomicInteger();
40        for (int i = 0; true; i++) {
41            try {
42                newThread(finalizedThreadsCount, 1024 << i).start();
43            } catch (OutOfMemoryError expected) {
44                break;
45            }
46        }
47        FinalizationTester.induceFinalization();
48        assertTrue("Started threads were never finalized!", finalizedThreadsCount.get() > 0);
49    }
50
51    public void testLeakingUnstartedThreads() {
52        final AtomicInteger finalizedThreadsCount = new AtomicInteger();
53        for (int i = 0; true; i++) {
54            try {
55                newThread(finalizedThreadsCount, 1024 << i);
56            } catch (OutOfMemoryError expected) {
57                break;
58            }
59        }
60        FinalizationTester.induceFinalization();
61        assertTrue("Unstarted threads were never finalized!", finalizedThreadsCount.get() > 0);
62    }
63
64    public void testThreadSleep() throws Exception {
65        int millis = 1000;
66        long start = System.currentTimeMillis();
67
68        Thread.sleep(millis);
69
70        long elapsed = System.currentTimeMillis() - start;
71        long offBy = Math.abs(elapsed - millis);
72
73        assertTrue("Actual sleep off by " + offBy + " ms", offBy <= 250);
74    }
75
76    public void testThreadInterrupted() throws Exception {
77        Thread.currentThread().interrupt();
78        try {
79            Thread.sleep(0);
80            fail();
81        } catch (InterruptedException e) {
82            assertFalse(Thread.currentThread().isInterrupted());
83        }
84    }
85
86    public void testThreadSleepIllegalArguments() throws Exception {
87
88        try {
89            Thread.sleep(-1);
90            fail();
91        } catch (IllegalArgumentException expected) {
92        }
93
94        try {
95            Thread.sleep(0, -1);
96            fail();
97        } catch (IllegalArgumentException expected) {
98        }
99
100        try {
101            Thread.sleep(0, 1000000);
102            fail();
103        } catch (IllegalArgumentException expected) {
104        }
105    }
106
107    public void testThreadWakeup() throws Exception {
108        WakeupTestThread t1 = new WakeupTestThread();
109        WakeupTestThread t2 = new WakeupTestThread();
110
111        t1.start();
112        t2.start();
113        assertTrue("Threads already finished", !t1.done && !t2.done);
114
115        t1.interrupt();
116        t2.interrupt();
117
118        Thread.sleep(1000);
119        assertTrue("Threads did not finish", t1.done && t2.done);
120    }
121
122    public void testContextClassLoaderIsNotNull() {
123        assertNotNull(Thread.currentThread().getContextClassLoader());
124    }
125
126    public void testContextClassLoaderIsInherited() {
127        Thread other = new Thread();
128        assertSame(Thread.currentThread().getContextClassLoader(), other.getContextClassLoader());
129    }
130
131    /**
132     * Thread.getStackTrace() is broken. http://b/1252043
133     */
134    public void testGetStackTrace() throws Exception {
135        Thread t1 = new Thread("t1") {
136            @Override public void run() {
137                doSomething();
138            }
139            public void doSomething() {
140                for (int i = 0; i < 20;) {
141                    try {
142                        Thread.sleep(100);
143                    } catch (InterruptedException ignored) {
144                    }
145                }
146            }
147        };
148        t1.start();
149        Thread.sleep(1000);
150        StackTraceElement[] traces = t1.getStackTrace();
151        StackTraceElement trace = traces[traces.length - 2];
152
153        // Expect to find MyThread.doSomething in the trace
154        assertTrue(trace.getClassName().contains("ThreadTest")
155                && trace.getMethodName().equals("doSomething"));
156    }
157
158    public void testGetAllStackTracesIncludesAllGroups() throws Exception {
159        final AtomicInteger visibleTraces = new AtomicInteger();
160        ThreadGroup group = new ThreadGroup("1");
161        Thread t2 = new Thread(group, "t2") {
162            @Override public void run() {
163                visibleTraces.set(Thread.getAllStackTraces().size());
164            }
165        };
166        t2.start();
167        t2.join();
168
169        // Expect to see the traces of all threads (not just t2)
170        assertTrue("Must have traces for all threads", visibleTraces.get() > 1);
171    }
172
173    // http://b/27748318
174    public void testNativeThreadNames() throws Exception {
175        String testResult = nativeTestNativeThreadNames();
176        // Not using assertNull here because this results in a better error message.
177        if (testResult != null) {
178            fail(testResult);
179        }
180    }
181
182    // This method returns {@code null} if all tests pass, or a non-null String containing
183    // failure details if an error occured.
184    private static native String nativeTestNativeThreadNames();
185
186    private Thread newThread(final AtomicInteger finalizedThreadsCount, final int size) {
187        return new Thread() {
188            long[] memoryPressure = new long[size];
189            @Override protected void finalize() throws Throwable {
190                super.finalize();
191                finalizedThreadsCount.incrementAndGet();
192            }
193        };
194    }
195
196    private class WakeupTestThread extends Thread {
197        public boolean done;
198
199        public void run() {
200            done = false;
201
202            // Sleep for a while (1 min)
203            try {
204                Thread.sleep(60000);
205            } catch (InterruptedException ignored) {
206            }
207
208            done = true;
209        }
210    }
211}
212