1 package jep.test;
2 
3 import jep.Interpreter;
4 import jep.JepConfig;
5 import jep.SubInterpreter;
6 
7 /**
8  * Tests that shared modules can be imported simultaneously on multiple threads.
9  * Python 3 requires careful synchronization to ensure that uninitialized
10  * modules are not inadvertantly shared.
11  *
12  * This test relies on multiple threads importing at the same time. If the OS
13  * thread scheduling gets lucky it might pass even if there are problems. We
14  * just assume that over the course of a release if it breaks eventually someone
15  * will see a failed test.
16  *
17  * Created: August 2016
18  *
19  * @author Ben Steffensmeier
20  */
21 public class TestSharedModulesThreads extends Thread {
22 
main(String[] args)23     public static void main(String[] args) throws Throwable {
24         TestSharedModulesThreads[] t = new TestSharedModulesThreads[16];
25         for (int i = 0; i < t.length; i += 1) {
26             t[i] = new TestSharedModulesThreads();
27             t[i].start();
28         }
29         for (int i = 0; i < t.length; i += 1) {
30             t[i].join();
31             if (t[i].e != null) {
32                 throw t[i].e;
33             }
34         }
35         /*
36          * Ensure that the shared moduler import hooks don't interfere with pure
37          * python threading. This use case is not well supported but it mostly
38          * works so this just checks for obvious flaws.
39          */
40         try (Interpreter interp = new SubInterpreter(
41                 new JepConfig().addIncludePaths(".")
42                         .addSharedModules("xml.etree.ElementTree"))) {
43             interp.eval("import threading");
44             interp.eval("success = False");
45             StringBuilder testFunction = new StringBuilder();
46             testFunction.append("def testFunction():\n");
47             testFunction.append("    global success\n");
48             testFunction.append("    import struct\n");
49             testFunction.append("    success = True");
50             interp.eval(testFunction.toString());
51             interp.eval("t = threading.Thread(target=testFunction)");
52             interp.eval("t.start()");
53             interp.eval("t.join()");
54             /*
55              * Sleep to workaround a python bug, that occasionally fails the
56              * test. Remove the sleep when 2.7 and 3.3 are no longer supported.
57              * https://bugs.python.org/issue18808
58              */
59             Thread.sleep(10);
60             Object success = interp.getValue("success");
61             if (!Boolean.TRUE.equals(success)) {
62                 System.exit(1);
63             }
64         }
65 
66     }
67 
68     public Exception e = null;
69 
70     @Override
run()71     public void run() {
72         try (Interpreter interp = new SubInterpreter(
73                 new JepConfig().addIncludePaths(".")
74                         .addSharedModules("xml.etree.ElementTree"))) {
75             interp.eval("import xml.etree.ElementTree");
76             interp.eval("t = xml.etree.ElementTree.ElementTree");
77         } catch (Exception e) {
78             this.e = e;
79         }
80     }
81 
82 }
83