1 2 Previous Next 26 Replies Latest reply on Nov 20, 2010 6:35 AM by kabirkhan

    Embedded AS

    kabirkhan

      I'm having a play with getting the demos working as tests, and thought it would be cool to be able to start standalone in-vm as was done in BatchFailuresUnitTestCase/AbstractDeploymentTest.

       

      The first problem I see is that when trying to use the StandaloneClient and calling SC.getServerModel() I get this exception:

       

      Exception in thread "pool-11-thread-2" java.util.ServiceConfigurationError: org.jboss.marshalling.ProviderDescriptor: Provider org.jboss.mar
      shalling.river.RiverProviderDescriptor could not be instantiated: java.lang.IllegalAccessError: tried to access class org.jboss.marshalling.
      reflect.ConcurrentReferenceHashMap from class org.jboss.marshalling.reflect.SerializableClassRegistry
      at java.util.ServiceLoader.fail(ServiceLoader.java:207)
      at java.util.ServiceLoader.access$100(ServiceLoader.java:164)
      at java.util.ServiceLoader$LazyIterator.next(ServiceLoader.java:353)
      at java.util.ServiceLoader$1.next(ServiceLoader.java:421)
      at org.jboss.marshalling.Marshalling.loadMarshallerFactory(Marshalling.java:78)
      at org.jboss.marshalling.Marshalling.getMarshallerFactory(Marshalling.java:74)
      at org.jboss.as.protocol.ProtocolUtils.<clinit>(ProtocolUtils.java:50)
      at org.jboss.as.protocol.mgmt.ManagementProtocolHeader.read(ManagementProtocolHeader.java:75)
      at org.jboss.as.protocol.mgmt.ManagementResponseHeader.read(ManagementResponseHeader.java:60)
      at org.jboss.as.protocol.mgmt.ManagementProtocolHeader.<init>(ManagementProtocolHeader.java:55)
      at org.jboss.as.protocol.mgmt.ManagementResponseHeader.<init>(ManagementResponseHeader.java:45)
      at org.jboss.as.protocol.mgmt.ManagementRequest$1.handle(ManagementRequest.java:124)
      at org.jboss.as.protocol.mgmt.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:59)
      at org.jboss.as.protocol.ConnectionImpl.safeHandleMessage(ConnectionImpl.java:239)
      at org.jboss.as.protocol.ConnectionImpl$1$1.run(ConnectionImpl.java:198)
      at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
      at java.lang.Thread.run(Thread.java:680)
      Caused by: java.lang.IllegalAccessError: tried to access class org.jboss.marshalling.reflect.ConcurrentReferenceHashMap from class org.jboss
      .marshalling.reflect.SerializableClassRegistry
      at org.jboss.marshalling.reflect.SerializableClassRegistry.<init>(SerializableClassRegistry.java:61)
      at org.jboss.marshalling.reflect.SerializableClassRegistry.<clinit>(SerializableClassRegistry.java:42)
      at org.jboss.marshalling.river.RiverMarshallerFactory$1.run(RiverMarshallerFactory.java:46)
      at org.jboss.marshalling.river.RiverMarshallerFactory$1.run(RiverMarshallerFactory.java:44)
      at java.security.AccessController.doPrivileged(Native Method)
      at org.jboss.marshalling.river.RiverMarshallerFactory.<init>(RiverMarshallerFactory.java:44)
      at org.jboss.marshalling.river.RiverProviderDescriptor.<clinit>(RiverProviderDescriptor.java:35)
      at java.lang.Class.forName0(Native Method)
      at java.lang.Class.forName(Class.java:247)
      at java.util.ServiceLoader$LazyIterator.next(ServiceLoader.java:345)
      ... 15 more

      Exception in thread "pool-11-thread-2" java.util.ServiceConfigurationError: org.jboss.marshalling.ProviderDescriptor: Provider org.jboss.mar

      shalling.river.RiverProviderDescriptor could not be instantiated: java.lang.IllegalAccessError: tried to access class org.jboss.marshalling.

      reflect.ConcurrentReferenceHashMap from class org.jboss.marshalling.reflect.SerializableClassRegistry

      at java.util.ServiceLoader.fail(ServiceLoader.java:207)

      at java.util.ServiceLoader.access$100(ServiceLoader.java:164)

      at java.util.ServiceLoader$LazyIterator.next(ServiceLoader.java:353)

      at java.util.ServiceLoader$1.next(ServiceLoader.java:421)

      at org.jboss.marshalling.Marshalling.loadMarshallerFactory(Marshalling.java:78)

      at org.jboss.marshalling.Marshalling.getMarshallerFactory(Marshalling.java:74)

      at org.jboss.as.protocol.ProtocolUtils.<clinit>(ProtocolUtils.java:50)

      at org.jboss.as.protocol.mgmt.ManagementProtocolHeader.read(ManagementProtocolHeader.java:75)

      at org.jboss.as.protocol.mgmt.ManagementResponseHeader.read(ManagementResponseHeader.java:60)

      at org.jboss.as.protocol.mgmt.ManagementProtocolHeader.<init>(ManagementProtocolHeader.java:55)

      at org.jboss.as.protocol.mgmt.ManagementResponseHeader.<init>(ManagementResponseHeader.java:45)

      at org.jboss.as.protocol.mgmt.ManagementRequest$1.handle(ManagementRequest.java:124)

      at org.jboss.as.protocol.mgmt.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:59)

      at org.jboss.as.protocol.ConnectionImpl.safeHandleMessage(ConnectionImpl.java:239)

      at org.jboss.as.protocol.ConnectionImpl$1$1.run(ConnectionImpl.java:198)

      at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)

      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)

      at java.lang.Thread.run(Thread.java:680)

      Caused by: java.lang.IllegalAccessError: tried to access class org.jboss.marshalling.reflect.ConcurrentReferenceHashMap from class org.jboss

      .marshalling.reflect.SerializableClassRegistry

      at org.jboss.marshalling.reflect.SerializableClassRegistry.<init>(SerializableClassRegistry.java:61)

      at org.jboss.marshalling.reflect.SerializableClassRegistry.<clinit>(SerializableClassRegistry.java:42)

      at org.jboss.marshalling.river.RiverMarshallerFactory$1.run(RiverMarshallerFactory.java:46)

      at org.jboss.marshalling.river.RiverMarshallerFactory$1.run(RiverMarshallerFactory.java:44)

      at java.security.AccessController.doPrivileged(Native Method)

      at org.jboss.marshalling.river.RiverMarshallerFactory.<init>(RiverMarshallerFactory.java:44)

      at org.jboss.marshalling.river.RiverProviderDescriptor.<clinit>(RiverProviderDescriptor.java:35)

      at java.lang.Class.forName0(Native Method)

      at java.lang.Class.forName(Class.java:247)

      at java.util.ServiceLoader$LazyIterator.next(ServiceLoader.java:345)

      ... 15 more

       

      ADT starts the server without using modules so everything uses the app classpath, so that may be the reason for the exception?

       

      I have created a little 'ServerStarter' module programatically from my tests and added that to the module roots of my LocalModuleLoader. The server is then started with the correct module classloader and most classes are loaded from the module I would expect. The exception is when a module that defines the 'system' dependency tries to load a class and it both exists on the app classpath and in a 'real' module. In this case the class is always loaded from 'system'.

       

      Looking at Module.loadModuleClass() the loaders for the path for this situation seem to always have SystemLocalLoader before the ModuleClassLoaders. Is this intentional? Is there another way to have things both in app classpath and in modules always be loaded by modules?

        • 1. Re: Embedded AS
          kabirkhan

          Talking to David, embedded stuff should always use the app classpath. I've got the server started but am seeing a few issues that I need to resolve

          • 2. Re: Embedded AS
            dmlloyd

            Well, any of the following solutions would work:

            1. Run embedded stuff in a fully modularized environment
            2. Put everything on the app classpath (and hope there's no duplicate dependencies...)
            3. Use a hybrid solution with a customized module repos where no packages are duplicated between modules and the app class path

             

            Just using the app classpath is the simplest, assuming you don't hit any duplicate issues.

            • 3. Re: Embedded AS
              kabirkhan

              I'm going for 2) for now. With a few changes -Dorg.jboss.as.embedded=true tells ModuleXmlParsers to only load extensions once, and ServerControllerOperationHandler to use its own cl when initializing the marshalling SimpleClassResolver.

               

              1) Sounds like a real pain :-)

              3) Might be possible once we have a cleaner separation between client and server classes

              • 4. Re: Embedded AS
                kabirkhan

                I've reworked the demos so they can be run as part of our testsuite: https://github.com/kabir/jboss-as/tree/demos-test-modules

                 

                This is not a pull request, there are still a few small issues that need looking at, just want to get your feedback/suggestions.

                 

                I first tried using the flat application classpath to do this. With some small modifications I was able to get an embedded instance to run in vm and to be able to connect to it via the standalone client. Those changes were changing how ServerControllerOperationHandler initializes its marshaller and how extensions are initialzed. However, trying the sar example I never saw the MBean get started, which is probably due to the sar deployer adding dependencies on some modules. David suggested adding/replacing these modules with something else to be able to make them use the system classpath.

                 

                What I have now is quite similar to how the protocol tests worked. Under testsuite/modular we have these projects

                 

                -common/ contains the test interfaces, e.g. DemosTest, and has nothing on the classpath

                -impl/ contains the real tests, e,g. DemosTestImpl which implements DemostTest, and has everything it needs to build on the classpath

                -assembly/ creates the test modules (more about this later)

                -test/ contains the tests run, e.g. DemosTestCase which delegates to DemosTestImpl via the DemosTest interface. It sets up the module loader roots and loads its test via the module loader.

                 

                This way when running the tests only jboss-modules, testsuite/module/common and junit are on the classpath.

                 

                The module roots used are:

                1) build/target/jboss-xxx/stanalone/modules - for the stanard AS modules

                2) assembly/target/modules - assembly creates modules for maven artifacts which don't exist in 1) and which are only available as maven dependencies, so they can't be constructed in 3).

                3) test/target/module_roots - These are modules created from other classes in the workspace, and are configured via annotations on the test interface from common/, e.g.:

                 

                @TestModules({

                        @TestModule(

                                moduleName="test.demos",

                                packages={@TestModulePackage(packages={"org.jboss.test.as.modular.impl.demos", "org.jboss.test.as.modular.impl"})},

                                dependencies= {"demos.archive", "org.jboss.as.messaging", "javax.jms.api"}),

                        @TestModule(

                                moduleName="demos.archive",

                                jars=@TestModuleJar (project="demos", jar="jboss-as-demos.*(?<!sources)\\.jar"),

                                dependencies= {"org.jboss.as.standalone-client", "org.jboss.as.testsuite.modular.shrinkwrap", "javaee.api", "org.jboss.as.protocol", "org.hornetq"}),

                        @TestModule (

                                moduleName="test.demos.tccl",

                                dependencies= {"org.jboss.as.testsuite.modular.shrinkwrap", "org.jboss.logging", "demos.archive"},

                                includeSystem=false)

                        }

                )

                @TestSetup(

                        implClass="org.jboss.test.as.modular.impl.demos.DemosTestImpl",

                        testModule="test.demos",

                        tcclModule="test.demos.tccl")

                public interface DemosTest extends ModularTest {

                    void testSar() throws Exception;

                    void testManagedBean() throws Exception;

                    ...

                }

                 

                This creates three modules:

                -test.demo - which is created from classes in those packages in the impl/ project

                -demos.archive - which is created from the examples we had in the demos/ project

                -test.demos.tccl - which is the modules that need to be part of the TCCL for ShrinkWrap to work. I've worked around https://jira.jboss.org/browse/MODULES-55 for now.

                 

                So the main thing is that while this works fine, setting up a test using modular classloading isn't exactly trivial. If someone has some ideas for how to programatically import maven dependencies we could get rid of assembly at least. But we would still have three parts per test. I'll look into creating a custom junit runner tomorrow, which might make the overall setup simpler.

                 

                If we go with something like this, should my final goal be Arquillian integration?

                 

                If the protocol tests get redone they should be moved into this framework.

                • 5. Re: Embedded AS
                  kabirkhan

                  I've played with a simple runner so I think we can do away with the common/ stuff

                   

                  This would leave us with assembly/ which can maybe be moved into impl/.

                   

                  We'd then end up with test/ which would just contain the skeleton test classes:

                   

                  @RunWith(ModularJunitTestRunner.class)

                  @TestModules({...})

                  @TestSetup(implClass="__ThrowawayTestImpl", ...)

                  public class __ThrowawayTestCase {

                     //No @Test methods, they are loaded from the Impl class

                  }

                   

                  and the real test in impl

                   

                  public class __ThrowawayTestImpl{

                      @Test

                      public void test1() {

                   

                      }

                   

                      @Test

                      public void test2() {

                   

                      }

                  }

                  This is better, but can it be made simpler somehow?

                  • 6. Re: Embedded AS
                    jason.greene

                    David Lloyd wrote:

                     

                    Well, any of the following solutions would work:

                    1. Run embedded stuff in a fully modularized environment
                    2. Put everything on the app classpath (and hope there's no duplicate dependencies...)
                    3. Use a hybrid solution with a customized module repos where no packages are duplicated between modules and the app class path

                     

                    Just using the app classpath is the simplest, assuming you don't hit any duplicate issues.

                    I had typed up this nice really well thought out post, but the forums decided to eat it. So instead I will summarize

                     

                    Basically I think 2 is a non-option as it will be brittle and it directly contradicts with our hide internal impl requirement. Not to mention if we are testing a client server protocol we actually do want the classes to be in separate loaders.

                     

                    The duplicate packages should be ok in the case of having the client protocol stuff on the classpath as that would only be used within the app classpath classloader. Really the only difference between 1 and 3 is whether or not the user has to define a module definition listing their package (3 discovers packages via the system module). So IMO 3 is the best long term option.

                    • 7. Re: Embedded AS
                      dmlloyd

                      Jason Greene wrote:

                       

                      David Lloyd wrote:

                       

                      Well, any of the following solutions would work:

                      1. Run embedded stuff in a fully modularized environment
                      2. Put everything on the app classpath (and hope there's no duplicate dependencies...)
                      3. Use a hybrid solution with a customized module repos where no packages are duplicated between modules and the app class path

                       

                      Just using the app classpath is the simplest, assuming you don't hit any duplicate issues.

                      I had typed up this nice really well thought out post, but the forums decided to eat it. So instead I will summarize

                       

                      Basically I think 2 is a non-option as it will be brittle and it directly contradicts with our hide internal impl requirement. Not to mention if we are testing a client server protocol we actually do want the classes to be in separate loaders.

                       

                      I don't think all our requirements apply for all embedded use cases.  That said I don't think that the flat-classpath embedded arrangement is suitable for testing our own stuff in most cases, but I think some users will want to do it that way.  I agree that long-term we should focus on encouraging users to run in a modularized environment.

                      • 8. Re: Embedded AS
                        kabirkhan

                        David Lloyd wrote:

                         

                        Jason Greene wrote:

                         

                        David Lloyd wrote:

                         

                        Well, any of the following solutions would work:

                        1. Run embedded stuff in a fully modularized environment
                        2. Put everything on the app classpath (and hope there's no duplicate dependencies...)
                        3. Use a hybrid solution with a customized module repos where no packages are duplicated between modules and the app class path

                         

                        Just using the app classpath is the simplest, assuming you don't hit any duplicate issues.

                        I had typed up this nice really well thought out post, but the forums decided to eat it. So instead I will summarize

                         

                        Basically I think 2 is a non-option as it will be brittle and it directly contradicts with our hide internal impl requirement. Not to mention if we are testing a client server protocol we actually do want the classes to be in separate loaders.

                         

                        I don't think all our requirements apply for all embedded use cases.  That said I don't think that the flat-classpath embedded arrangement is suitable for testing our own stuff in most cases, but I think some users will want to do it that way.  I agree that long-term we should focus on encouraging users to run in a modularized environment.

                         

                        For our tests I am going with 1 (or really 3), the custom test runner makes it a lot nicer and easier than what I had before.

                         

                        Once this has taken a bit more shape, I would like to extract the embedded startup into an embedded/ module with options for starting embedded AS in both flat and modular modes so that it can be consumed directly, at the moment this is hidden away in the testsuite.

                        • 9. Re: Embedded AS
                          kabirkhan
                          What I have so far can be found at https://github.com/kabir/jboss-as/commits/demos-test-embedded-cleaned. I still need to go through and add privileged actions etc. before this can be pushed, but some feedback before finalizing this would be great.
                          The embedded stuff can be used with either flat or modular classloading. I'll talk about flat first since that is the simplest.
                          To start up an embedded server you simply create an instance of org.jboss.as.embedded.FlatEmbeddedServer and start that up as shown in org.jboss.test.as.embedded.flat.RunServerTestCase in embedded/flat:
                                  System.setProperty("jboss.embedded.server.home", Utils.getASHome().getAbsolutePath());
                                  System.setProperty("jboss.embedded.server.modules", new File(Utils.getASHome(), "modules").getAbsolutePath());
                                  FlatEmbeddedServer server = new FlatEmbeddedServer();
                                  try {
                                      server.start();
                                      ServerModel model = server.getClient().getServerModel();
                                      Assert.assertNotNull(model);
                                  } finally {
                                      System.clearProperty("jboss.embedded.server.home");
                                      System.clearProperty("jboss.embedded.server.modules");
                                      server.shutdown();
                                  }
                          The thing I had to do here to get it to work is to take the jboss.embedded.server.modules location, and copy that to a new location replacing the module.xml for each module with:
                          <?xml version="1.0" encoding="UTF-8"?>
                          <module xmlns="urn:jboss:module:1.0" name="org.jboss.logging">
                              <dependencies>
                                  <module name="system" export="true"/>
                              </dependencies>
                          </module>
                          So every module delegates to the system classloader. If the default module loader could be swapped out somehow in jboss-modules, I could come up with a more elegant solution for this if deemed important.
                          To run using modular classloading you need two projects:
                          1) The implementation which starts the server and does the useful stuff. It contains all the dependencies to be able to compile that. This can be found in testsuite/modular/impl and depends on the stuff from embedded/modular/server
                          2) The bootstrap which is used to construct the module loader seeing the as modules and additional modules created per test. This does not have the implementation on the classpath but loads this up via modules. The bootstrap lives in testsuite/modular/test and has a simple classpath just containing things needed to be able to load the classes to be able to construct the test modules with no dependencies on things that should be loaded up via modules (found in embedded/modular/bootstrap).
                          The main way to run a test is shown in testsuite/modular/test/org.jboss.test.as.modular.demos.test.DemosTestCase:
                          @TestSetup(
                              implClass="org.jboss.test.as.modular.demos.impl.DemosTestImpl",
                              testModule="test.demos",
                              tcclModule="test.demos.tccl",
                              systemPropertyProvider=DemoSystemPropertyProvider.class,
                              modules= {
                                  @ModuleDef(
                                          name="test.demos",
                                          packages={@PackageResource(directory="${demo.impl.classes}", packages={"org.jboss.test.as.modular.demos.impl"})},
                                          jars=@JarResource (directory="${project.root}/demos/target", jar="jboss-as-demos.*(?<!sources)\\.jar", expand=true),
                                          dependencies= {@Dependency("javaee.api"), @Dependency("org.hornetq"), @Dependency("org.jboss.as.messaging"), @Dependency("javax.jms.api")}),
                                  @ModuleDef (
                                          name="test.demos.tccl",
                                          dependencies= {@Dependency("org.jboss.logging"), @Dependency("test.demos")})
                                  }
                          )
                          @RunWith(ModularJunitTestRunner.class)
                          public class DemosTestCase {
                          }
                          The ModularJunitTestRunner picks up @TestSetup and creates:
                          -a module called 'test.demos' with some classes from testsuite/impl project and the jar from the demos project. Since this is the same name as 'testModule' the dependencies needed to start a server are added automatically, but since we need access to some more classes to run the demos that have been ported so far some more are added using the 'dependencies'.
                          -a module called 'test.demos.tccl' that is used as the TCCL when running each test (Shrinkwrap currently relies on TCCL)
                          ModularJunitTestRunner then loads up org.jboss.test.as.modular.demos.impl.DemosTestImpl from the test.demos module and runs that which contains the real tests:
                          public class DemosTestImpl  {
                              static ModularEmbeddedServer starter = new ModularEmbeddedServer(getASHome());
                              @BeforeClass
                              public static void startServer() throws Exception {
                                  starter.start(JMSSubsystemElement.JMS_CF_BASE.append("InVmConnectionFactory").getCanonicalName());
                              }
                              @AfterClass
                              public static void stopServer() throws Exception {
                                  starter.shutdown();
                              }
                              @Test
                              public void testSar() throws Exception {
                                  SarTestRunner runner = new SarTestRunner(starter);
                                  runner.test();
                              }
                              …
                          }
                          testsuite/modular/test/org.jboss.test.as.modular.embedded.test.ModuleBuilderTestCase shows how to use the ModuleLoaderBuilder directly (not recommended) or the more friendly ModularEmbeddedServerBuilder for users who want to bootstrap an AS instance from their code.

                          What I have so far can be found at https://github.com/kabir/jboss-as/commits/demos-test-embedded-cleaned. I still need to go through and add privileged actions etc. before this can be pushed, but some feedback before finalizing this would be great.

                           

                          The embedded stuff can be used with either flat or modular classloading. I'll talk about flat first since that is the simplest.

                           

                          To start up an embedded server you simply create an instance of org.jboss.as.embedded.FlatEmbeddedServer and start that up as shown in org.jboss.test.as.embedded.flat.RunServerTestCase in embedded/flat:

                           

                                  System.setProperty("jboss.embedded.server.home", Utils.getASHome().getAbsolutePath());

                                  System.setProperty("jboss.embedded.server.modules", new File(Utils.getASHome(), "modules").getAbsolutePath());

                                  FlatEmbeddedServer server = new FlatEmbeddedServer();

                                  try {

                                      server.start();

                                      ServerModel model = server.getClient().getServerModel();

                                      Assert.assertNotNull(model);

                                  } finally {

                                      System.clearProperty("jboss.embedded.server.home");

                                      System.clearProperty("jboss.embedded.server.modules");

                                      server.shutdown();

                                  }

                           

                          The thing I had to do here to get it to work is to take the jboss.embedded.server.modules location, and copy that to a new location replacing the module.xml for each module with:

                           

                          <?xml version="1.0" encoding="UTF-8"?>

                          <module xmlns="urn:jboss:module:1.0" name="org.jboss.logging">

                              <dependencies>

                                  <module name="system" export="true"/>

                              </dependencies>

                          </module>

                           

                          So every module delegates to the system classloader. If the default module loader could be swapped out somehow in jboss-modules, I could come up with a more elegant solution for this if deemed important.

                           

                          To run using modular classloading you need two projects:

                          1. The implementation which starts the server and does the useful stuff. It contains all the dependencies to be able to compile that. This can be found in testsuite/modular/impl and depends on the stuff from embedded/modular/server
                          2. The bootstrap which is used to construct the module loader seeing the as modules and additional modules created per test. This does not have the implementation on the classpath but loads this up via modules. The bootstrap lives in testsuite/modular/test and has a simple classpath just containing things needed to be able to load the classes to be able to construct the test modules with no dependencies on things that should be loaded up via modules (found in embedded/modular/bootstrap).

                           

                          The main way to run a test is shown in testsuite/modular/test/org.jboss.test.as.modular.demos.test.DemosTestCase:

                           

                          @TestSetup(

                              implClass="org.jboss.test.as.modular.demos.impl.DemosTestImpl",

                              testModule="test.demos",

                              tcclModule="test.demos.tccl",

                              systemPropertyProvider=DemoSystemPropertyProvider.class,

                              modules= {

                                  @ModuleDef(

                                          name="test.demos",

                                          packages={@PackageResource(directory="${demo.impl.classes}", packages={"org.jboss.test.as.modular.demos.impl"})},

                                          jars=@JarResource (directory="${project.root}/demos/target", jar="jboss-as-demos.*(?<!sources)\\.jar", expand=true),

                                          dependencies= {@Dependency("javaee.api"), @Dependency("org.hornetq"), @Dependency("org.jboss.as.messaging"), @Dependency("javax.jms.api")}),

                                  @ModuleDef (

                                          name="test.demos.tccl",

                                          dependencies= {@Dependency("org.jboss.logging"), @Dependency("test.demos")})

                                  }

                          )

                          @RunWith(ModularJunitTestRunner.class)

                          public class DemosTestCase {

                          }

                           

                          The ModularJunitTestRunner picks up @TestSetup and creates:

                          -a module called 'test.demos' with some classes from testsuite/impl project and the jar from the demos project. Since this is the same name as 'testModule' the dependencies needed to start a server are added automatically, but since we need access to some more classes to run the demos that have been ported so far some more are added using the 'dependencies'.

                          -a module called 'test.demos.tccl' that is used as the TCCL when running each test (Shrinkwrap currently relies on TCCL)

                           

                          ModularJunitTestRunner then loads up org.jboss.test.as.modular.demos.impl.DemosTestImpl from the test.demos module and runs that which contains the real tests:

                          public class DemosTestImpl  {

                           

                              static ModularEmbeddedServer starter = new ModularEmbeddedServer(getASHome());

                           

                              @BeforeClass

                              public static void startServer() throws Exception {

                                  starter.start(JMSSubsystemElement.JMS_CF_BASE.append("InVmConnectionFactory").getCanonicalName());

                              }

                           

                              @AfterClass

                              public static void stopServer() throws Exception {

                                  starter.shutdown();

                              }

                           

                              @Test

                              public void testSar() throws Exception {

                                  SarTestRunner runner = new SarTestRunner(starter);

                                  runner.test();

                              }

                              …

                          }

                           

                          The nice thing about this is that coding a test requires no command-line building of the test modules, you can write/modify/run tests directly in your IDE.

                           

                          testsuite/modular/test/org.jboss.test.as.modular.embedded.test.ModuleBuilderTestCase shows how to use the ModuleLoaderBuilder directly (not recommended) or the more friendly ModularEmbeddedServerBuilder for users who want to bootstrap an AS instance from their code.

                          • 10. Re: Embedded AS
                            kabirkhan

                            I forgot to mention the TCCL module is currently a hack, while waiting for https://jira.jboss.org/browse/MODULES-55

                            • 11. Re: Embedded AS
                              kabirkhan

                              I think instead of the names picking out the relevant modules like I have

                               

                              @TestSetup(

                                  implClass="org.jboss.test.as.modular.demos.impl.DemosTestImpl",

                                  testModule="test.demos",

                                  tcclModule="test.demos.tccl",

                                  systemPropertyProvider=DemoSystemPropertyProvider.class,

                                  modules= {

                                      @ModuleDef(

                                              name="test.demos",

                                              packages={@PackageResource(directory="${demo.impl.classes}", packages={"org.jboss.test.as.modular.demos.impl"})},

                                              jars=@JarResource (directory="${project.root}/demos/target", jar="jboss-as-demos.*(?<!sources)\\.jar", expand=true),

                                              dependencies= {@Dependency("javaee.api"), @Dependency("org.hornetq"), @Dependency("org.jboss.as.messaging"), @Dependency("javax.jms.api")}),

                                      @ModuleDef (

                                              name="test.demos.tccl",

                                              dependencies= {@Dependency("org.jboss.logging"), @Dependency("test.demos")})

                                      }

                              )

                               

                              They should be defined inline instead

                               

                              @TestSetup(

                                  implClass="org.jboss.test.as.modular.demos.impl.DemosTestImpl",

                                  testModule=@ModuleDef(

                                              name="test.demos",

                                              packages={@PackageResource(directory="${demo.impl.classes}", packages={"org.jboss.test.as.modular.demos.impl"})},

                                              jars=@JarResource (directory="${project.root}/demos/target", jar="jboss-as-demos.*(?<!sources)\\.jar", expand=true),

                                              dependencies= {@Dependency("javaee.api"), @Dependency("org.hornetq"), @Dependency("org.jboss.as.messaging"),

                                  tcclModule=@ModuleDef (

                                              name="test.demos.tccl",

                                              dependencies= {@Dependency("org.jboss.logging"), @Dependency("test.demos")})

                                      },

                                  systemPropertyProvider=DemoSystemPropertyProvider.class,

                                  modules= {}

                              )

                               

                              modules then can be used for the unusual case where people need to define more modules

                              • 12. Re: Embedded AS
                                brian.stansberry

                                Is the separate "TestImpl" source file required (e.g. org.jboss.test.as.modular.demos.impl.DemosTestImpl)? It seems like ModularJUnitRunner uses DemosTestCase as the source of the @TestSetup annotation, loads a class from the module it creates, and passes that class to its superclass as the class to test. As long as the module ModularJUnitRunner creates doesn't end up loading that class from the app classloader, it's a separate class. So you shouldn't need a separate source file for the actual test implementation.

                                 

                                I'm going to play a bit and see.

                                • 13. Re: Embedded AS
                                  brian.stansberry

                                  Nope; trying to get rid of the separate DemosTestImpl doesn't work at all. If you do that, everything's visible via the SystemModuleLoader and you end up getting LinkageError, IllegalAccessError and the like.

                                  • 14. Re: Embedded AS
                                    brian.stansberry

                                    Essentially what you're doing with the separate DemosTestImpl class and the separate "modular-test" maven module is trying to control what's on the app classpath. That feels like something the test framework could do itself. I took a shot at that; see https://github.com/bstansberry/jboss-as/commit/2d5ef5c15d1c5fbb664c7ba2b89fbc79cffdc0d6#diff-0 .

                                     

                                    I got further with that than I did before, but am getting this failure. I'm hoping it's something simple.

                                     

                                    java.lang.ExceptionInInitializerError
                                        at org.jboss.as.embedded.modular.server.ModularEmbeddedServer.start(ModularEmbeddedServer.java:165)
                                        at org.jboss.test.as.modular.demos.impl.DemosTestCase.startServer(DemosTestCase.java:67)
                                        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                                        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
                                        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
                                        at java.lang.reflect.Method.invoke(Method.java:597)
                                        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
                                        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
                                        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
                                        at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:27)
                                        at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
                                        at org.junit.runners.ParentRunner.run(ParentRunner.java:220)
                                        at org.jboss.as.embedded.modular.bootstrap.DelegatingModularJunitTestRunner.run(DelegatingModularJunitTestRunner.java:116)
                                        at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
                                        at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
                                        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
                                        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
                                        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
                                        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
                                    Caused by: java.lang.IllegalStateException: The LogManager was not properly installed (you must set the "java.util.logging.manager" system property to "org.jboss.logmanager.LogManager")
                                        at org.jboss.logmanager.Logger.getLogger(Logger.java:60)
                                        at org.jboss.logging.JBossLogManagerProvider.doGetLogger(JBossLogManagerProvider.java:55)
                                        at org.jboss.logging.JBossLogManagerProvider.getLogger(JBossLogManagerProvider.java:46)
                                        at org.jboss.logging.Logger.getLogger(Logger.java:2222)
                                        at org.jboss.as.server.StandaloneServer.<clinit>(StandaloneServer.java:48)
                                        ... 19 more

                                     

                                    BTW, ModularEmbeddedServer.shutdown() then throws an NPE because it assumes the serverController field was initialized:

                                     

                                    java.lang.NullPointerException
                                        at org.jboss.as.embedded.modular.server.ModularEmbeddedServer.shutdown(ModularEmbeddedServer.java:185)
                                        at org.jboss.test.as.modular.demos.impl.DemosTestCase.stopServer(DemosTestCase.java:73)
                                    1 2 Previous Next