1edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# Run the _testcapi module tests (tests for the Python/C API):  by defn,
2edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep# these are all functions _testcapi exports whose name begins with 'test_'.
3edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
4edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepfrom __future__ import with_statement
5edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepimport sys
6edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepimport time
7edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepimport random
8edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepimport unittest
9edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepfrom test import test_support
10edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoeptry:
11edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    import thread
12edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    import threading
13edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepexcept ImportError:
14edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    thread = None
15edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    threading = None
16edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepimport _testcapi
17edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
18edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep@unittest.skipUnless(threading, 'Threading required for this test.')
19edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass TestPendingCalls(unittest.TestCase):
20edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
21edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def pendingcalls_submit(self, l, n):
22edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        def callback():
23edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            #this function can be interrupted by thread switching so let's
24edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            #use an atomic operation
25edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            l.append(None)
26edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
27edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        for i in range(n):
28edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            time.sleep(random.random()*0.02) #0.01 secs on average
29edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            #try submitting callback until successful.
30edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            #rely on regular interrupt to flush queue if we are
31edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            #unsuccessful.
32edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            while True:
33edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                if _testcapi._pending_threadfunc(callback):
34edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                    break;
35edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
36edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def pendingcalls_wait(self, l, n, context = None):
37edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        #now, stick around until l[0] has grown to 10
38edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        count = 0;
39edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        while len(l) != n:
40edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            #this busy loop is where we expect to be interrupted to
41edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            #run our callbacks.  Note that callbacks are only run on the
42edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            #main thread
43edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            if False and test_support.verbose:
44edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                print "(%i)"%(len(l),),
45edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            for i in xrange(1000):
46edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                a = i*i
47edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            if context and not context.event.is_set():
48edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                continue
49edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            count += 1
50edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            self.assertTrue(count < 10000,
51edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                "timeout waiting for %i callbacks, got %i"%(n, len(l)))
52edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        if False and test_support.verbose:
53edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            print "(%i)"%(len(l),)
54edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
55edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_pendingcalls_threaded(self):
56edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        #do every callback on a separate thread
57edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        n = 32 #total callbacks
58edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        threads = []
59edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        class foo(object):pass
60edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        context = foo()
61edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        context.l = []
62edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        context.n = 2 #submits per thread
63edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        context.nThreads = n // context.n
64edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        context.nFinished = 0
65edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        context.lock = threading.Lock()
66edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        context.event = threading.Event()
67edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
68edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        for i in range(context.nThreads):
69edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            t = threading.Thread(target=self.pendingcalls_thread, args = (context,))
70edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            t.start()
71edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            threads.append(t)
72edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
73edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.pendingcalls_wait(context.l, n, context)
74edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
75edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        for t in threads:
76edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            t.join()
77edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
78edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def pendingcalls_thread(self, context):
79edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        try:
80edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            self.pendingcalls_submit(context.l, context.n)
81edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        finally:
82edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            with context.lock:
83edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                context.nFinished += 1
84edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                nFinished = context.nFinished
85edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                if False and test_support.verbose:
86edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                    print "finished threads: ", nFinished
87edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            if nFinished == context.nThreads:
88edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                context.event.set()
89edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
90edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_pendingcalls_non_threaded(self):
91edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        #again, just using the main thread, likely they will all be dispatched at
92edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        #once.  It is ok to ask for too many, because we loop until we find a slot.
93edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        #the loop can be interrupted to dispatch.
94edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        #there are only 32 dispatch slots, so we go for twice that!
95edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        l = []
96edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        n = 64
97edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.pendingcalls_submit(l, n)
98edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        self.pendingcalls_wait(l, n)
99edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
100edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
101edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep@unittest.skipUnless(threading and thread, 'Threading required for this test.')
102edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepclass TestThreadState(unittest.TestCase):
103edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
104edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    @test_support.reap_threads
105edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    def test_thread_state(self):
106edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        # some extra thread-state tests driven via _testcapi
107edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        def target():
108edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            idents = []
109edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
110edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            def callback():
111edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                idents.append(thread.get_ident())
112edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
113edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            _testcapi._test_thread_state(callback)
114edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            a = b = callback
115edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            time.sleep(1)
116edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            # Check our main thread is in the list exactly 3 times.
117edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            self.assertEqual(idents.count(thread.get_ident()), 3,
118edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                             "Couldn't find main thread correctly in the list")
119edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
120edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        target()
121edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        t = threading.Thread(target=target)
122edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        t.start()
123edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        t.join()
124edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
125edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
126edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepdef test_main():
127edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    for name in dir(_testcapi):
128edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep        if name.startswith('test_'):
129edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            test = getattr(_testcapi, name)
130edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            if test_support.verbose:
131edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                print "internal", name
132edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            try:
133edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                test()
134edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep            except _testcapi.error:
135edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep                raise test_support.TestFailed, sys.exc_info()[1]
136edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
137edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    test_support.run_unittest(TestPendingCalls, TestThreadState)
138edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep
139edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoepif __name__ == "__main__":
140edbb763a2b63074cd468a5d33a17908b2cc0654Jeff Vander Stoep    test_main()
141