Skip to content

Commit 2abae88

Browse files
committed
Introduce integration JUnit tests
The integration tests depend only on the embedding polyglot APIs, unlike the regular JUnit tests, which have access to the GraalPy/Truffle internals. (cherry picked from commit 0d2f5fd)
1 parent 7e840fe commit 2abae88

File tree

77 files changed

+1588
-814
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

77 files changed

+1588
-814
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,4 @@ graalpython.tests.src.zip.files/
8484
graalpython.src.zip.files/
8585
graalpython/com.oracle.graal.python.test/src/tests/patched_package/build/
8686
graalpython/com.oracle.graal.python.test/src/tests/patched_package/src/patched_package.egg-info
87+
graalpython/com.oracle.graal.python.test.integration/target

graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/CleanupRule.java renamed to graalpython/com.oracle.graal.python.test.integration/src/com/oracle/graal/python/test/integration/CleanupRule.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3939
* SOFTWARE.
4040
*/
41-
package com.oracle.graal.python.test;
41+
package com.oracle.graal.python.test.integration;
4242

4343
import java.util.ArrayList;
4444

graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/EngineOptionsTests.java renamed to graalpython/com.oracle.graal.python.test.integration/src/com/oracle/graal/python/test/integration/EngineOptionsTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3939
* SOFTWARE.
4040
*/
41-
package com.oracle.graal.python.test;
41+
package com.oracle.graal.python.test.integration;
4242

4343
import static org.junit.Assert.assertEquals;
4444

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
/*
2+
* Copyright (c) 2017, 2023, Oracle and/or its affiliates.
3+
* Copyright (c) 2013, Regents of the University of California
4+
*
5+
* All rights reserved.
6+
*
7+
* Redistribution and use in source and binary forms, with or without modification, are
8+
* permitted provided that the following conditions are met:
9+
*
10+
* 1. Redistributions of source code must retain the above copyright notice, this list of
11+
* conditions and the following disclaimer.
12+
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
13+
* conditions and the following disclaimer in the documentation and/or other materials provided
14+
* with the distribution.
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
17+
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18+
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19+
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20+
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21+
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22+
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23+
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
24+
* OF THE POSSIBILITY OF SUCH DAMAGE.
25+
*/
26+
package com.oracle.graal.python.test.integration;
27+
28+
import static org.hamcrest.CoreMatchers.containsString;
29+
import static org.junit.Assert.assertEquals;
30+
import static org.junit.Assert.assertTrue;
31+
32+
import java.io.ByteArrayOutputStream;
33+
import java.io.File;
34+
import java.io.IOException;
35+
import java.io.InputStream;
36+
import java.io.InputStreamReader;
37+
import java.io.OutputStream;
38+
import java.io.PrintStream;
39+
import java.util.Collections;
40+
import java.util.Map;
41+
42+
import org.graalvm.polyglot.Context;
43+
import org.graalvm.polyglot.Engine;
44+
import org.graalvm.polyglot.PolyglotException;
45+
import org.graalvm.polyglot.Source;
46+
import org.graalvm.polyglot.Value;
47+
import org.junit.Assert;
48+
49+
import com.oracle.graal.python.test.integration.advanced.BenchmarkTests;
50+
51+
public class PythonTests {
52+
private static final Source PRINT_EXC_TO_STDERR = Source.create("python", "import traceback; traceback.print_exception");
53+
54+
static final ByteArrayOutputStream errArray = new ByteArrayOutputStream();
55+
static final ByteArrayOutputStream outArray = new ByteArrayOutputStream();
56+
static final PrintStream errStream = new PrintStream(errArray);
57+
static final PrintStream outStream = new PrintStream(outArray);
58+
59+
private static final Engine engine = Engine.newBuilder().out(PythonTests.outStream).err(PythonTests.errStream).build();
60+
private static Context context = null;
61+
62+
public static Context enterContext(String... newArgs) {
63+
return enterContext(Collections.emptyMap(), newArgs);
64+
}
65+
66+
public static Context enterContext(Map<String, String> options, String[] args) {
67+
PythonTests.outArray.reset();
68+
PythonTests.errArray.reset();
69+
Context prevContext = context;
70+
context = Context.newBuilder().engine(engine).allowExperimentalOptions(true).allowAllAccess(true).options(options).arguments("python", args).build();
71+
context.initialize("python");
72+
assert prevContext == null;
73+
context.enter();
74+
return context;
75+
}
76+
77+
private static void closeContext(Context ctxt) {
78+
try {
79+
ctxt.leave();
80+
} catch (RuntimeException e) {
81+
}
82+
ctxt.close();
83+
}
84+
85+
public static void closeContext() {
86+
if (context != null) {
87+
closeContext(context);
88+
context = null;
89+
}
90+
}
91+
92+
public static void assertLastLineError(String expected, String code) {
93+
final ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
94+
final PrintStream printStream = new PrintStream(byteArray);
95+
String source = code;
96+
PythonTests.runThrowableScript(new String[0], source, System.out, printStream);
97+
String[] output = byteArray.toString().split("\n");
98+
// ignore the traceback
99+
assertEquals(expected.trim(), output[output.length - 1].trim());
100+
}
101+
102+
public static void assertLastLineErrorContains(String expected, String code) {
103+
final ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
104+
final PrintStream printStream = new PrintStream(byteArray);
105+
String source = code;
106+
PythonTests.runThrowableScript(new String[0], source, System.out, printStream);
107+
String[] output = byteArray.toString().split("\n");
108+
// ignore the traceback
109+
Assert.assertThat(output[output.length - 1], containsString(expected.trim()));
110+
}
111+
112+
public static void assertPrintContains(String expected, String code) {
113+
final ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
114+
final PrintStream printStream = new PrintStream(byteArray);
115+
String source = code;
116+
PythonTests.runScript(new String[0], source, printStream, System.err);
117+
String result = byteArray.toString().replaceAll("\r\n", "\n");
118+
assertTrue(result.contains(expected));
119+
}
120+
121+
public static void assertPrints(String expected, String code) {
122+
final ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
123+
final PrintStream printStream = new PrintStream(byteArray);
124+
PythonTests.runScript(new String[0], code, printStream, System.err);
125+
String result = byteArray.toString().replaceAll("\r\n", "\n");
126+
assertEquals(expected.replaceAll(" at 0x[0-9a-f]*>", " at 0xabcd>"), result.replaceAll(" at 0x[0-9a-f]*>", " at 0xabcd>"));
127+
}
128+
129+
public static void assertPrints(String expected, Source code) {
130+
final ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
131+
final PrintStream printStream = new PrintStream(byteArray);
132+
PythonTests.runScript(new String[0], code, printStream, System.err);
133+
String result = byteArray.toString().replaceAll("\r\n", "\n");
134+
assertEquals(expected.replaceAll(" at 0x[0-9a-f]*>", " at 0xabcd>"), result.replaceAll(" at 0x[0-9a-f]*>", " at 0xabcd>"));
135+
}
136+
137+
public static Value eval(String code) {
138+
final ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
139+
final PrintStream printStream = new PrintStream(byteArray);
140+
return PythonTests.runScript(new String[0], code, printStream, System.err);
141+
}
142+
143+
static void flush(OutputStream out, OutputStream err) {
144+
PythonTests.outStream.flush();
145+
PythonTests.errStream.flush();
146+
try {
147+
out.write(PythonTests.outArray.toByteArray());
148+
err.write(PythonTests.errArray.toByteArray());
149+
} catch (IOException e) {
150+
throw new RuntimeException(e);
151+
}
152+
}
153+
154+
public static Source createSource(String source) {
155+
return Source.newBuilder("python", source, "Unnamed").buildLiteral();
156+
}
157+
158+
public static Source createSource(File path) throws IOException {
159+
return Source.newBuilder("python", path).build();
160+
}
161+
162+
public static Value runScript(String[] args, File path, OutputStream out, OutputStream err) {
163+
try {
164+
enterContext(args);
165+
return context.eval(createSource(path));
166+
} catch (IOException e) {
167+
e.printStackTrace();
168+
throw new RuntimeException(e);
169+
} finally {
170+
flush(out, err);
171+
closeContext();
172+
}
173+
}
174+
175+
public static Value runScript(Map<String, String> options, String[] args, String source, OutputStream out, OutputStream err) {
176+
try {
177+
enterContext(options, args);
178+
return context.eval(createSource(source));
179+
} finally {
180+
flush(out, err);
181+
closeContext();
182+
}
183+
}
184+
185+
public static Value runScript(String[] args, String source, OutputStream out, OutputStream err) {
186+
try {
187+
enterContext(args);
188+
return context.eval(createSource(source));
189+
} finally {
190+
flush(out, err);
191+
closeContext();
192+
}
193+
}
194+
195+
public static Value runScript(String[] args, Source source, OutputStream out, OutputStream err) {
196+
try {
197+
enterContext(args);
198+
return context.eval(source);
199+
} finally {
200+
flush(out, err);
201+
closeContext();
202+
}
203+
}
204+
205+
public static Value runScript(String[] args, String source, OutputStream out, OutputStream err, Runnable cb) {
206+
return runScript(Collections.emptyMap(), args, source, out, err, cb);
207+
}
208+
209+
public static Value runScript(Map<String, String> options, String[] args, String source, OutputStream out, OutputStream err, Runnable cb) {
210+
try {
211+
enterContext(options, args);
212+
return context.eval(createSource(source));
213+
} finally {
214+
cb.run();
215+
flush(out, err);
216+
closeContext();
217+
}
218+
}
219+
220+
public static void runThrowableScript(String[] args, String source, OutputStream out, OutputStream err) {
221+
try {
222+
enterContext(args);
223+
context.eval(createSource(source));
224+
} catch (PolyglotException t) {
225+
try {
226+
Value printExc = context.eval(PRINT_EXC_TO_STDERR);
227+
printExc.execute(t.getGuestObject());
228+
} catch (Throwable ex) {
229+
throw new RuntimeException("Error while printing the PolyglotException message to stderr.", ex);
230+
}
231+
} finally {
232+
flush(out, err);
233+
closeContext();
234+
}
235+
}
236+
237+
public static Source getScriptSource(String name) {
238+
InputStream is = BenchmarkTests.class.getClassLoader().getResourceAsStream("com/oracle/graal/python/test/integration/scripts/" + name);
239+
try {
240+
return Source.newBuilder("python", new InputStreamReader(is), name).build();
241+
} catch (IOException e) {
242+
throw new RuntimeException(e);
243+
}
244+
}
245+
}

graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/advance/AsyncActionThreadingTest.java renamed to graalpython/com.oracle.graal.python.test.integration/src/com/oracle/graal/python/test/integration/advanced/AsyncActionThreadingTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3939
* SOFTWARE.
4040
*/
41-
package com.oracle.graal.python.test.advance;
41+
package com.oracle.graal.python.test.integration.advanced;
4242

4343
import static org.junit.Assert.assertEquals;
4444
import static org.junit.Assert.assertTrue;
@@ -52,7 +52,7 @@
5252
import org.junit.Assume;
5353
import org.junit.Test;
5454

55-
import com.oracle.graal.python.test.PythonTests;
55+
import com.oracle.graal.python.test.integration.PythonTests;
5656

5757
public class AsyncActionThreadingTest extends PythonTests {
5858
long pythonThreadCount() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright (c) 2017, 2021, Oracle and/or its affiliates.
3+
* Copyright (c) 2014, Regents of the University of California
4+
*
5+
* All rights reserved.
6+
*
7+
* Redistribution and use in source and binary forms, with or without modification, are
8+
* permitted provided that the following conditions are met:
9+
*
10+
* 1. Redistributions of source code must retain the above copyright notice, this list of
11+
* conditions and the following disclaimer.
12+
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
13+
* conditions and the following disclaimer in the documentation and/or other materials provided
14+
* with the distribution.
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
17+
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18+
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19+
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20+
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21+
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22+
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23+
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
24+
* OF THE POSSIBILITY OF SUCH DAMAGE.
25+
*/
26+
package com.oracle.graal.python.test.integration.advanced;
27+
28+
import static org.junit.Assert.assertEquals;
29+
import static org.junit.Assert.assertNotEquals;
30+
31+
import java.io.ByteArrayOutputStream;
32+
import java.io.PrintStream;
33+
34+
import org.graalvm.polyglot.Source;
35+
import org.junit.Test;
36+
37+
import com.oracle.graal.python.test.integration.PythonTests;
38+
39+
public class BenchmarkTests {
40+
@Test
41+
public void richards3() {
42+
String name = "richards3.py";
43+
assertBenchNoError(name, new String[]{name, "20"});
44+
}
45+
46+
@Test
47+
public void bm_ai() {
48+
String name = "ai-nqueen.py";
49+
assertBenchNoError(name, new String[]{name, "5"});
50+
}
51+
52+
@Test
53+
public void mandelbrot3_300() {
54+
String name = "mandelbrot3.py";
55+
assertBenchNoError(name, new String[]{name, "200"});
56+
}
57+
58+
public static void assertBenchNoError(String scriptName, String[] args) {
59+
final ByteArrayOutputStream byteArrayErr = new ByteArrayOutputStream();
60+
final ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
61+
final PrintStream printErrStream = new PrintStream(byteArrayErr);
62+
final PrintStream printOutStream = new PrintStream(byteArrayOut);
63+
Source source = PythonTests.getScriptSource(scriptName);
64+
if (args == null) {
65+
PythonTests.runScript(new String[]{source.toString()}, source, printOutStream, printErrStream);
66+
} else {
67+
args[0] = source.toString();
68+
PythonTests.runScript(args, source, printOutStream, printErrStream);
69+
}
70+
71+
String err = byteArrayErr.toString().replaceAll("\r\n", "\n");
72+
String result = byteArrayOut.toString().replaceAll("\r\n", "\n");
73+
System.out.println(scriptName + "\n" + result + "\n");
74+
assertEquals("", err);
75+
assertNotEquals("", result);
76+
}
77+
}

graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/advance/MultiContextTest.java renamed to graalpython/com.oracle.graal.python.test.integration/src/com/oracle/graal/python/test/integration/advanced/MultiContextTest.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,13 @@
3838
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3939
* SOFTWARE.
4040
*/
41-
package com.oracle.graal.python.test.advance;
41+
package com.oracle.graal.python.test.integration.advanced;
4242

4343
import org.graalvm.polyglot.Context;
4444
import org.graalvm.polyglot.Engine;
4545
import org.junit.Test;
4646

47-
import com.oracle.graal.python.test.PythonTests;
47+
import com.oracle.graal.python.test.integration.PythonTests;
4848

4949
public class MultiContextTest extends PythonTests {
5050
@Test
@@ -63,7 +63,8 @@ public void testSharingWithStruct() {
6363
// backend for the first context, but then it is going to use the Sulong backend for
6464
// consecutive contexts (as long as this is the only test that executes native code,
6565
// which it seems to be). This is why we need "sulong:SULONG_NATIVE" among the
66-
// dependencies for GRAALPYTHON_UNIT_TESTS distribution
66+
// dependencies for GRAALPYTHON_UNIT_TESTS distribution, and
67+
// org.graalvm.polyglot:llvm-community dependency in the pom.xml
6768
Engine engine = Engine.newBuilder().build();
6869
for (int i = 0; i < 10; i++) {
6970
try (Context context = newContext(engine)) {

0 commit comments

Comments
 (0)