Hi Stuart,

    thanks a lot for the comments!

-Felix
On 2016/4/28 9:06, Stuart Marks wrote:
Hi Felix,

I finally got a chance to take a good look at this. Again, sorry for the delays. I was able to reproduce the failure and find a fix for it. There are also some structural issues with the test that will require some improvements.

* * *

First is the way the test fixture is set up. The test now has a single copy of the source code for the client, server, and app, and they're compiled once. This is good. Unfortunately, the tests modify the filesystem in order to set up different cases for the classes' modular structure.

The problem is that makes the tests dependent on each other. The Test-NG directives enforce this execution order, but it makes them really hard to work with. For example, if I were to disable test #2, this would cause test #3 to fail since #3 depends on side effects from test #2. Also, if test #2 were to fail, it's hard to debug, since test #3 modifies the fixture after test #2 runs, potentially obscuring any problems that #2 might have run into.

Ideally the test should set up a single test fixture and not modify it, allowing the different cases to be run independently. Offhand I'm not sure of the best way to do this.

One approach that might be worth exploring is to create several different jar files from the class files; the jar files would have the classes in different modular configurations. Then, each test would invoke a JVM with arguments to put the different jar files on the classpath or the module path. I haven't investigated this approach, though, so I don't know if it's practical.

Other approaches may be viable as well. It's probably worth discussing and prototyping an approach first before you spend too much time implementing any particular scheme.
It was chosen to compile once considering efficiency. If we prefer each test can be executed separately, it looks enough to just change "@BeforeTest" to "@BeforeMethod" and update tests slightly. With jar files, may I understand it is a different scenario with automatic modules. I suggest to add a new test in future enhancement.

See http://cr.openjdk.java.net/~xiaofeya/8078812/webrev.02

-Felix

* * *

Moving on to the actual test failure, the message from testUnnamedApp() is as follows:

==================================================
Command line: [/Users/src/jdk-dev/jdk9-dev/build/macosx-x86_64-normal-server-fastdebug/jdk/bin/java -ea -esa -mp mods -Djava.rmi.server.codebase=file:/Users/src/jdk-dev/jdk9-dev/jdk/testoutput/JTwork/java/rmi/module/ModuleTest/./mods/mserver/ -cp classes testpkg.DummyApp 65071 ]

Error: A JNI error has occurred, please check your installation and try again Exception in thread "main" java.lang.NoClassDefFoundError: serverpkg/Hello
    at java.lang.Class.getDeclaredMethods0(java.base/Native Method)
at java.lang.Class.privateGetDeclaredMethods(java.base/Class.java:2937) at java.lang.Class.privateGetMethodRecursive(java.base/Class.java:3282)
    at java.lang.Class.getMethod0(java.base/Class.java:3252)
    at java.lang.Class.getMethod(java.base/Class.java:1961)
at sun.launcher.LauncherHelper.validateMainClass(java.base/LauncherHelper.java:648) at sun.launcher.LauncherHelper.checkAndLoadMain(java.base/LauncherHelper.java:499)
Caused by: java.lang.ClassNotFoundException: serverpkg.Hello
at jdk.internal.loader.BuiltinClassLoader.loadClass(java.base/BuiltinClassLoader.java:366) at jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(java.base/ClassLoaders.java:184)
    at java.lang.ClassLoader.loadClass(java.base/ClassLoader.java:419)
    ... 7 more

test ModuleTest.testUnnamedApp(): failure
java.lang.AssertionError: expected [0] but found [1]
        [remainder of stack trace elided]
==================================================

The main class is testpkg.DummyApp, but the launcher fails with NoClassDefFoundError on serverpkg/Hello. This was a bit of a puzzle, but I finally figured out that this is occurring during the verification of the DummyApp class. DummyApp depends on Hello, which can't be found, so it fails verification before DummyApp.main() gets called.

It's also strange that it says "A JNI error has occurred" but that might be a red herring.

In any case the real issue is that serverpkg.Hello can't be found. The reason it can't be found is that it's in a module. That module is on the module path, but the module isn't resolved by default. Thus its classes aren't visible to classes in the unnamed module.

To add modules to the set of resolved modules, use the -addmods option. In this case, testUnnamedApp() has the client and server classes in modules, so it needs to have the arguments

    -addmods mclient,mserver

added to its command line. Since the mclient module explicitly depends on the mserver module, this could instead just e

    -addmods mclient

The testUnnamedAppandClient() method has only the server in a named module, so it needs to have

    -addmods mserver

on its command line.

With these changes, all the tests pass.
Thanks for figuring this out. But do you think it is worth to investigate the " NoClassDefFoundError " and "A JNI error has occurred". The root cause is not well-indicated.

-Felix

* * *

There are a couple other things that could be improved as well. I'll just mention them here (so I don't forget) but we should work on these later:

1) The registry and codebase stuff is probably unnecessary and can be removed. These might be interesting test cases for the future. It's not clear to me that we need to support modules in the RMI codebase, but at least there should be tests for cases we think are important.
Excuse me, could you explain what to remove in detail? I agree the scenarios can be various beyond the sanity ones.

-Felix

2) In DummyApp, if creating the Client fails (e.g., because of NoClassDefFoundError), that error will propagate out of the main() method, bypassing the calls to System.exit(). The Server object has already been exported, which will cause the JVM to live indefinitely. This causes the test to hang and eventually time out, and to leave stale JVM processes after the test run.
There is explicit System.exit(-1) for error situation, so I didn't observe such stale process. Any way, I updated it slightly.

-Felix

In any case, I think the next step is to come up with a good design for varying the modular structure of the classes for the different test cases, without modifying the filesystem. Let's work on that, and we can work on the other stuff later.

s'marks





On 4/14/16 1:45 AM, Felix Yang wrote:
Hi Stuart,
     any comment on the new tests and issue?

Thanks,
Felix
On 2016/4/8 15:52, Felix Yang wrote:
Hi Stuart,
thanks for the comments. I adjusted the test. The test failed with NoClassDefFoundErr if client/server are in named module but dummy app in
unnamed module. See https://bugs.openjdk.java.net/browse/JDK-8153833

New webrev: http://cr.openjdk.java.net/~xiaofeya/8078812/webrev.01/
<http://cr.openjdk.java.net/%7Exiaofeya/8078812/webrev.01/>

About simplifying the scenario, I replaced inheritance by moving classes in
runtime.

Thanks,
Felix

On 2016/3/2 10:28, Stuart Marks wrote:
Hi Felix, sorry for the delay.

Several comments below.

--------------------------------------------------

 119         // wait for rmiregistry to be fully ready
 120         Thread.sleep(3000);

There are some RMI test utilities that will handle starting up and waiting for the registry to be ready. Unfortunately they're in the unnamed package
(still haven't cleaned that up) so you can't use them from this test.

For now I'd recommend scaling the timeout by the test.timeout.factor, so that
this won't fail on slow systems. There's a test utility for that; see
Utils.adjustTimeout().

--------------------------------------------------

The directory "unamed" is misspelled; it has classes in the unnamed module.
This misspelling is reflected in variable names and values, e.g.,

59 private static final Path UNAMED_SRC_DIR = Paths.get(TEST_SRC,
"unamed");
60 private static final Path MODS_OUTPUT_DIR = Paths.get("mods"); 61 private static final Path UNAMED_OUTPUT_DIR = Paths.get("unamed");

While spelling errors aren't that big a deal, since this involves file and directory names, I'd recommend fixing this now. It'll just be harder to fix
it later.

Also, "SeperateModuleClient" => "SeparateModuleClient"

--------------------------------------------------

Overall the structure of the test seems reasonable to test various clients and servers in combinations of the same, different, and unnamed modules.

I'm not entirely sure what p2.SeperateModuleClient is testing. It extends
p1.Client and its constructor and testStub() method simply call the
corresponding methods on super, so it doesn't seem to be testing anything
different from p1.Client running against p3.Server.

Also, p4.UnamedModuleClient seems to want to run the client from the unnamed module, but it too extends p1.Client and simply defers all of its execution to its superclass. So I don't think this actually testing an RMI client call
originating from an unnamed module.

There is an uncomfortable amount of duplication between
mtest/test/DummyApp.java and p4/UnamedModuleDummyApp. I see what this is
trying to do, which is to test a RMI server from an unnamed module. It
instantiates p3.Server, which resides in a named module, but exports it from
an unnamed module.

So I think there's some tension here. There's subclassing among the clients that attempts to avoid duplication, which is good, but it doesn't truly seem to be testing clients in different modules and in an unnamed module. The
server, on the other hand, does seem to be testing things properly in
different modules, at the cost of duplicating all the code into another class
that resides in a different (unnamed) module.

I'm not entirely sure what the best approach is here. Ideally you'd want to
have a single implementation of client, server + remote interface, and
application, and compile each of them once. Then since you're invoking a new JVM for each test, invoke it with different options to put the client, or the server, or the app, into modules, or onto the classpath (to get into an unnamed module). You might have to copy compiled class files to different locations so that different classes can be either on the classpath or in a
named module without causing any conflicts.

I'm willing to entertain some simplifications here as well. It might be
sufficient to deal with just clients and servers in different/unnamed
modules, and not worry about putting the application into different modules.
That should reduce the number of cases to cover.

s'marks

On 2/29/16 10:05 PM, Felix Yang wrote:
Ping...

-Felix
On 2016/2/24 14:06, Felix Yang wrote:
Hi all,
      please review the new tests to use RMI in module world.

Webrev:
http://cr.openjdk.java.net/~xiaofeya/8078812/webrev.00/
Bug:
https://bugs.openjdk.java.net/browse/JDK-8078812

Thanks,
Felix




Reply via email to