MVP of new coroutine scheduler
diff --git a/core/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/scheduling/CoroutineSchedulerTest.kt b/core/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/scheduling/CoroutineSchedulerTest.kt
new file mode 100644
index 0000000..d8dad31
--- /dev/null
+++ b/core/kotlinx-coroutines-core/src/test/kotlin/kotlinx/coroutines/experimental/scheduling/CoroutineSchedulerTest.kt
@@ -0,0 +1,119 @@
+package kotlinx.coroutines.experimental.scheduling
+
+import kotlinx.coroutines.experimental.*
+import org.junit.After
+import org.junit.Test
+import java.util.concurrent.atomic.AtomicBoolean
+import kotlin.test.assertEquals
+import kotlin.test.assertNull
+
+class CoroutineSchedulerTest : TestBase() {
+
+    var dispatcher: ExperimentalCoroutineDispatcher? = null
+
+    @After
+    fun tearDown() {
+        schedulerTimeSource = NanoTimeSource
+        dispatcher?.close()
+    }
+
+    @Test
+    fun testSingleThread() = runBlocking {
+        dispatcher = ExperimentalCoroutineDispatcher(1)
+        expect(1)
+        withContext(dispatcher!!) {
+            require(Thread.currentThread().name.contains("CoroutinesScheduler-worker"))
+            expect(2)
+            val job = async(coroutineContext) {
+                expect(3)
+                delay(10)
+                expect(4)
+            }
+
+            job.await()
+            expect(5)
+        }
+
+        finish(6)
+    }
+
+    @Test
+    fun testStealing() = runBlocking {
+        dispatcher = ExperimentalCoroutineDispatcher(2)
+        val flag = AtomicBoolean(false)
+        val job = async(context = dispatcher!!) {
+            expect(1)
+            val innerJob = async {
+                expect(2)
+                flag.set(true)
+            }
+
+            while (!flag.get()) {
+                Thread.yield() // Block current thread, submitted inner job will be stolen
+            }
+
+            innerJob.await()
+            expect(3)
+        }
+
+        job.await()
+        finish(4)
+    }
+
+    @Test
+    fun testNoStealing() = runBlocking {
+        dispatcher = ExperimentalCoroutineDispatcher()
+        schedulerTimeSource = TestTimeSource(0L)
+        withContext(dispatcher!!) {
+            val thread = Thread.currentThread()
+            val job = async(dispatcher!!) {
+                assertEquals(thread, Thread.currentThread())
+                val innerJob = async(dispatcher!!) {
+                    assertEquals(thread, Thread.currentThread())
+                }
+                innerJob.await()
+            }
+
+            job.await()
+            assertEquals(thread, Thread.currentThread())
+        }
+    }
+
+    @Test
+    fun testDelay() = runBlocking {
+        dispatcher = ExperimentalCoroutineDispatcher(2)
+        withContext(dispatcher!!) {
+            expect(1)
+            delay(10)
+            expect(2)
+        }
+
+        finish(3)
+    }
+
+    @Test
+    fun testWithTimeout() = runBlocking {
+        dispatcher = ExperimentalCoroutineDispatcher()
+        withContext(dispatcher!!) {
+            expect(1)
+            val result = withTimeoutOrNull(1000) {
+                expect(2)
+                yield() // yield only now
+                "OK"
+            }
+            assertEquals("OK", result)
+
+            val nullResult = withTimeoutOrNull(1000) {
+                expect(3)
+                while (true) {
+                    yield()
+                }
+
+                "OK"
+            }
+
+            assertNull(nullResult)
+            finish(4)
+        }
+    }
+}