Karm / mandrel-integration-tests

Integration tests for GraalVM and its Mandrel distribution. Runs Quarkus, Helidon and Micronaut applications and small targeted reproducers. The focus is solely on native-image utility and compilation of Java applications into native executables.
Apache License 2.0
5 stars 3 forks source link

imageio testfix after dynamic AWT change for 23.0 was incomplete #151

Closed jerboaa closed 1 year ago

jerboaa commented 1 year ago

After https://github.com/Karm/mandrel-integration-tests/pull/146, we still see imageio test failures in CI:

2023-04-12 11:12:41.242 INFO  [o.g.t.i.AppReproducersTest] (imageioAWT) Running...
Error:  Tests run: 12, Failures: 1, Errors: 0, Skipped: 5, Time elapsed: 576.106 s <<< FAILURE! - in org.graalvm.tests.integration.AppReproducersTest
Error:  imageioAWTTest{TestInfo}  Time elapsed: 133.032 s  <<< FAILURE!
org.opentest4j.AssertionFailedError: 
There were errors checking the generated image files, see:
mytest.jpg was not generated.
mytest.bmp was not generated.
mytest.gif was not generated.
mytest.svg was not generated.
mytest.png was not generated.
mytest.tiff was not generated.
mytest_Resized_Grace_M._Hopper.png was not generated.
mytest.wbmp was not generated. ==> expected: <true> but was: <false>
    at org.graalvm.tests.integration.AppReproducersTest.imageioAWT(AppReproducersTest.java:594)
    at org.graalvm.tests.integration.AppReproducersTest.imageioAWTTest(AppReproducersTest.java:494)

[INFO] 
[INFO] Results:
[INFO] 
Error:  Failures: 
Error:    AppReproducersTest.imageioAWTTest:494->imageioAWT:594 There were errors checking the generated image files, see:
mytest.jpg was not generated.
mytest.bmp was not generated.
mytest.gif was not generated.
mytest.svg was not generated.
mytest.png was not generated.
mytest.tiff was not generated.
mytest_Resized_Grace_M._Hopper.png was not generated.
mytest.wbmp was not generated. ==> expected: <true> but was: <false>
[INFO] 
Error:  Tests run: 18, Failures: 1, Errors: 0, Skipped: 5
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary for Native image integration TS 1.0.0-SNAPSHOT:
[INFO] 
[INFO] Native image integration TS ........................ SUCCESS [  0.882 s]
[INFO] testsuite .......................................... FAILURE [29:40 min]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  29:41 min
[INFO] Finished at: 2023-04-12T11:12:46Z
[INFO] ------------------------------------------------------------------------
Error:  Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.22.2:test (default-test) on project testsuite: There are test failures.
Error:  
Error:  Please refer to /home/runner/work/mandrel/mandrel/mandrel-integration-tests/testsuite/target/surefire-reports for the individual test results.
Error:  Please refer to dump files (if any exist) [date].dump, [date]-jvmRun[N].dump and [date].dumpstream.
Error:  -> [Help 1]
Error:  
Error:  To see the full stack trace of the errors, re-run Maven with the -e switch.
Error:  Re-run Maven using the -X switch to enable full debug logging.
Error:  
Error:  For more information about the errors and possible solutions, please read the following articles:
Error:  [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
Error:  
Error:  After correcting the problems, you can resume the build with the command
Error:    mvn <args> -rf :testsuite
Error: Process completed with exit code 1.

As it turns out this is nothing CI specific (Ubuntu), but was an error in my testing of #146 where I had a lib directory in the app/imageio directory of my local clone of mandrel-integration-tests. Removing that empty directory reproduces this fine on Fedora too.

jerboaa commented 1 year ago

Looking at buildAndRun.log file it fails with (for native):

Exception in thread "main" java.io.IOException: Problem reading font data.
    at java.desktop@17.0.7-beta/java.awt.Font.createFont0(Font.java:1208)
    at java.desktop@17.0.7-beta/java.awt.Font.createFont(Font.java:1076)
    at imageio.Main.loadFonts(Main.java:139)
    at imageio.Main.paintRectangles(Main.java:97)
    at imageio.Main.main(Main.java:195)
jerboaa commented 1 year ago

What happens is this:

In https://github.com/openjdk/jdk17u/blob/908cab4123812b6b206b966a6ce92398cdf42c08/src/java.desktop/unix/classes/sun/awt/X11FontManager.java#L686..L707 there is this code:

 /* The logic here decides whether to use a preconfigured
         * fontconfig.properties file, or synthesise one using platform APIs.
         * On Solaris we try to use the
         * pre-configured ones, but if the files it specifies are missing
         * we fail-safe to synthesising one. This might happen if Solaris
         * changes its fonts.
         * For Linux we require an exact match of distro and version to
         * use the preconfigured file.
         * If synthesising fails, we fall back to any preconfigured file
         * and do the best we can.
         */
        FontConfiguration mFontConfig = new MFontConfiguration(this);
        if ((FontUtilities.isLinux && !mFontConfig.foundOsSpecificFile())) {
            FcFontConfiguration fcFontConfig =
                new FcFontConfiguration(this);
            if (fcFontConfig.init()) {
                return fcFontConfig; // <--- returns here for JVM mode
            }
        }
        mFontConfig.init(); // <--- reaches here for native mode
        return mFontConfig;

So why is the if condition entered for JVM mode, but not for native?

Remember, that we set java.home == . for native by setting -Djava.home=. Now, looking at the conditions, we note FontUtilities.isLinux && !mFontConfig.foundOsSpecificFile(). The former expression is true in both cases for native and JVM mode, but for native the latter is false. Why? foundOsSpecificFile() is just returning a boolean which is set to true by default. It's set to false here: https://github.com/openjdk/jdk17u/blob/908cab4123812b6b206b966a6ce92398cdf42c08/src/java.desktop/share/classes/sun/awt/FontConfiguration.java#L322. Yet, this never happens in native mode, because ${java.home}/lib doesn't exist (unless it so happens that ./lib exists), while for JVM mode it always does since a lib directory is part of the basic dir structure of a JDK image!

I.e. we return here in native mode and never set foundOsSpecificFile to false. Therefore, reaching the mFontConfig.init() case and throwing the NPE ultimately causing the java.io.IOException: Problem reading font data. problem. See https://github.com/Karm/mandrel-integration-tests/issues/151#issuecomment-1516780148

Therefore, creating an empty directory lib (or conf/fonts for that matter) in java.home is sufficient to fix this issue. At that point JVM mode and native mode take the same code path and the test passes.

jerboaa commented 1 year ago

Therefore, creating an empty directory lib (or conf/fonts for that matter) in java.home is sufficient to fix this issue. At that point JVM mode and native mode take the same code path and the test passes.

So in a way, @Karm, you were right about it here: https://github.com/Karm/mandrel-integration-tests/issues/102#issuecomment-1508395675

But at least I now know why it fixes the issue ;-)