1 2 Previous Next 24 Replies Latest reply on May 21, 2012 8:44 PM by dan.j.allen

    Towards Spring Test Enricher Milesone One

    jmnarloch

      After yesterday discussion with Marius we agreed to prepare the first release of the Spring test enricher (currently held here:https://github.com/jmnarloch/arquillian-container-spring) that will be ready within next 2-3 weeks.

       

      This version will include:

      • Current implemented functionality (that already includes custom context classes and auto packaging of the snowdrop for Spring 2.5.6)
      • Additional unit tests
      • Extending and merging the existing integration tests into single repository.
      • Preparing the showcase that would demonstrate the usage.
      • Preparing an article about using Arquillian for testing Spring applications.

       

      The next release could benefit from build in transaction support, but I wish to open separate discussion for that.

        • 1. Re: Towards Spring Test Enricher Milesone One
          jmnarloch

          After a week the unit tests are done both with a set of simple examples that demonstrates the usage (https://github.com/jmnarloch/arquillian-container-spring-showcase).

           

          What is left to do:

          1. Merge the integration test with the main repository.
          2. Prepare additional examples for the showcase that will present runing test together with:
            • JDBC
            • Hibernate
            • JPA
            • EJB
            • JMS
          • 2. Re: Towards Spring Test Enricher Milesone One
            jmnarloch

            The integration tests are now the "integral" part of the enricher: https://github.com/jmnarloch/arquillian-container-spring.

            • 3. Re: Towards Spring Test Enricher Milesone One
              dan.j.allen

              This is great work Jakub. Seriously.

               

              When I was debugging the tests on Embedded GlassFish, I noticed what appears to be duplicate Spring JAR files in the test archive in the Spring 2.5 integration test suite. Here's the contents of one of the test archives:

               

              WEB-INF/lib/spring-web-2.5.6.SEC02.jar
              WEB-INF/lib/spring-web-2.5.6.jar
              WEB-INF/lib/spring-core-2.5.6.SEC02.jar
              WEB-INF/lib/arquillian-protocol.jar
              WEB-INF/lib/arquillian-testenricher-msc.jar
              WEB-INF/lib/spring-context-support-2.5.6.SEC02.jar
              WEB-INF/lib/spring-beans-2.5.6.SEC02.jar
              WEB-INF/lib/arquillian-testenricher-ejb.jar
              WEB-INF/lib/spring-core-2.5.6.jar
              WEB-INF/lib/aopalliance-1.0.jar
              WEB-INF/lib/spring-context-2.5.6.jar
              WEB-INF/lib/snowdrop-vfs-2.0.3.Final.jar
              WEB-INF/lib/arquillian-junit.jar
              WEB-INF/lib/spring-context-2.5.6.SEC02.jar
              WEB-INF/lib/arquillian-testenricher-spring.jar
              WEB-INF/lib/arquillian-testenricher-resource.jar
              WEB-INF/lib/arquillian-testenricher-osgi.jar
              WEB-INF/lib/spring-test.jar
              WEB-INF/lib/spring-webmvc-2.5.6.SEC02.jar
              WEB-INF/lib/spring-beans-2.5.6.jar
              WEB-INF/lib/arquillian-testenricher-cdi.jar
              WEB-INF/lib/commons-logging-1.1.1.jar
              WEB-INF/lib/arquillian-core.jar
              WEB-INF/lib/arquillian-testenricher-initialcontext.jar
              

               

              I'm not sure if the files containing SEC02 should be there or not (or whether they should be replacing the matching libraries w/o this qualifier).

               

              You can examine the archive by adding the following snippet to the arquillian.xml file:

               

              <engine>
                  <property name="deploymentExportPath">target/test-archives</property>
              </engine>
              
              • 4. Re: Towards Spring Test Enricher Milesone One
                jmnarloch

                The answer appears to be that this are the Snowdrop dependencies.

                 

                There are marked as optional, but they are still resolved by default by MavenDependencyResolver.

                I'm going to see if marking the dependencies with optional() method will make a difference.

                • 5. Re: Towards Spring Test Enricher Milesone One
                  jmnarloch

                  It's more likely that I'll have to use MavenResolutionFilter.

                  • 6. Re: Towards Spring Test Enricher Milesone One
                    dan.j.allen

                    The optional flag in your pom.xml is orthogonal to the ShrinkWrap Resolver (and the underlying Aether). When it's iterating over the dependencies of snowdrop, it's looking to see if they are marked as optional in Snowdrop's pom, not the project pom. There's a chance that putting the Spring jars in dependencyManagement would allow you to override it, but that's highly dependent on Maven and the user's dependency setup.

                     

                    You are correct, MavenResolutionFilter is one way to approach this problem. The other possible solution is to use exclusions when resolving Snowdrop.

                     

                    However, I think the third solution I'll propose is the best. If Snowdrop is being included, allow it to resolve the Spring dependencies (that way they match). If Snowdrop is not included, then resolve the Spring dependencies explicitly.

                     

                    Here's how I envision the logic:

                     

                    if (getConfiguration().isIncludeSnowdrop()) {
                        // adds the snowdrop for testing within JBoss AS
                        // also determines the version of Spring to use through transitive resolution
                        mavenDependencyBuilder.addDependency(Spring25ExtensionConsts.SNOWDROP_ARTIFACT_NAME,
                                getConfiguration().getSnowdropVersion(), Spring25ExtensionConsts.SNOWDROP_ARTIFACT_VERSION);
                    }
                    else {
                        // adds the spring-context dependencies
                        mavenDependencyBuilder.addDependency(Spring25ExtensionConsts.SPRING_ARTIFACT_NAME,
                                getConfiguration().getSpringVersion(), Spring25ExtensionConsts.SPRING_ARTIFACT_VERSION);
                        
                        // adds spring web dependencies
                        mavenDependencyBuilder.addDependency(Spring25ExtensionConsts.SPRING_ARTIFACT_WEB_NAME,
                                getConfiguration().getSpringVersion(), Spring25ExtensionConsts.SPRING_ARTIFACT_VERSION);
                    }
                    
                    • 7. Re: Towards Spring Test Enricher Milesone One
                      dan.j.allen

                      Btw, if you wanted to go the exclusion route, you can use glob patterns, something that Maven doesn't support natively:

                       

                      mvnDependencyResolver.artifacts(artifact).exclusions("org.springframework:*").resolveAsFiles()
                      

                       

                      The exclusion, of course, would be a value you would have to pass down through the addDependency() method.

                       

                      However, I still say that you want to allow Snowdrop to resolve the Spring libraries...otherwise you could end up with a case where they become mismatched.

                       

                      There is one final option. If you really want to allow the Spring version to be specified (perhaps a point release), then both snowdrop and the spring libraries need to be passed to the same artifacts() call and the resolver will figure out that the higher version number should win. That's probably how your dependency builder class should work anyway. You are currently loading the resolver for each artifact, when you should be able to use the same resolver throughout.

                       

                      ...hopefully that gives you enough ideas.

                      • 8. Re: Towards Spring Test Enricher Milesone One
                        jmnarloch


                        That's probably how your dependency builder class should work anyway. You are currently loading the resolver for each artifact, when you should be able to use the same resolver throughout.

                         

                        ...hopefully that gives you enough ideas.

                        This is actually how it was done in the begining the MavenDependencyResolver  was declared as a field.

                        But during the execution it appeared that each subsequest call for MavenDependencyResolver#artifacts fails in case that the previouse one failed and there is also the method:

                         

                        {code}

                        private File[] resolveArtifact(String artifact, String version) {

                                File[] artifacts = null;

                                try {

                                    artifacts = resolveArtifact(artifact);

                                } catch (Exception e) {

                                    artifacts = resolveArtifact(artifact + ":" + version);

                                }

                                return artifacts;

                            }

                        {code}

                         

                        It tries to retrieve the artifact using the version from the pom file. In some situations the first call of  artifacts = resolveArtifact(artifact); will not work so I had to change that and instantiate the MavenDependencyResolver each time the method is invoked.

                        • 9. Re: Towards Spring Test Enricher Milesone One
                          jmnarloch

                          Promoting the mvnDependencyResolver into a field in MavenDependencyBuilder causes fallowing result:

                           

                           

                          {code}

                          Tests in error:

                            testProcessJarAutoPackageTrue(org.jboss.arquillian.spring.client.SpringProtocolArchiveProcessorTestCase): Unable to create artifact from coordinates cglib:cglib, they are either invalid or version information was not specified in loaded POM file (maybe the POM file wasn't load at all)

                            testProcessJarAutoPackageFalse(org.jboss.arquillian.spring.client.SpringProtocolArchiveProcessorTestCase): Unable to create artifact from coordinates cglib:cglib, they are either invalid or version information was not specified in loaded POM file (maybe the POM file wasn't load at all)

                            testProcessWarAutoPackageTrue(org.jboss.arquillian.spring.client.SpringProtocolArchiveProcessorTestCase): Unable to create artifact from coordinates cglib:cglib, they are either invalid or version information was not specified in loaded POM file (maybe the POM file wasn't load at all)

                            testProcessWarAutoPackageFalse(org.jboss.arquillian.spring.client.SpringProtocolArchiveProcessorTestCase): Unable to create artifact from coordinates cglib:cglib, they are either invalid or version information was not specified in loaded POM file (maybe the POM file wasn't load at all)

                          {code}

                           

                          Maybe I can overcome this and try to do a litlle hack, something like:

                           

                           

                          {code}

                          private void resolveArtifact(String artifact, String version) {

                                  if(canResolveArtifact(artifact)) {


                                    resolveArtifact(artifact);

                                  } else {


                                    resolveArtifact(artifact + ":" + version);

                                  }   

                          }

                          {code}

                          • 10. Re: Towards Spring Test Enricher Milesone One
                            dan.j.allen

                            I see your delimma about an exception in the resolution chain. This could be a good issue to bring up with Karel since they are in the midst of a design review for ShrinkWrap Resolvers.

                             

                            You have another interesting use case as well. I think ShrinkWrap Resolvers should accept an optional version and deal with it internally. I see what you are shooting for. You want to allow the version from the project's pom to be honored, but if a version isn't declared there, then you want to use the explicit version. This really is a fantastic use case to raise to Karel & the team.

                             

                            ...for now, I think it's probably fine just to leave it how it was but implement the two exclusion approaches I suggested (a: let snowdrop resolve the spring version or b: exclude org.springframework:* when resolving the snowdrop artifact).

                            • 11. Re: Towards Spring Test Enricher Milesone One
                              dan.j.allen

                              Since you are nearing a first preview release, I'd like to talk about naming. We are heading into some new territory with the Spring extension as far as terminology goes and it's important to get this right.

                               

                              First, some general naming requests:

                               

                              1. Relocate the @Spring*Configuration annotations to one of these packages (in preference order):

                              • org.jboss.arquillian.spring.api.annotation (consistent with Drone)
                              • org.jboss.arquillian.spring.test.api (consistent with Core)
                              • org.jboss.arquillian.spring.test.annotation (merge the two concepts)

                              (I'm open to ideas here).

                               

                              2. Rename *Consts classes

                              • rename SpringExtensionConsts to SpringExtensionConstants
                              • rename Spring3ExtensionConsts to SpringExtensionConstants_3
                              • rename Spring25ExtensionConsts to SpringExtensionConstants_2_5

                               

                              3. Should we use the term extension in the root package name: org.jboss.arquillian.extension.spring? Drone doesn't follow this convention, but it would be more consistent.

                               

                              Now, for the most visible names, the artifactIds.

                               

                              As I mentioned earlier, the Spring extension is the first of it's kind. It will provide:

                               

                              1. a packager/enricher, which I refer to as either a "service" or a "deployer"
                              2. an embedded runtime, which I refer to as an "embedded service container"

                               

                              This leads me to suggest the following artifactId for #1:

                               

                              • org.jboss.arquillian.extension:arquillian-deployer-spring-3 (currently org.jboss.arquillian.extension:arquillian-spring-3)
                              • org.jboss.arquillian.extension:arquillian-deployer-spring-2.5 (currently org.jboss.arquillian.extension:arquillian-spring-3)

                               

                              I'm not sure "deployer" is the right word here. Another possibility is "service", because it's as though you are installing the Spring service into the container. I guess "subsystem" would work as well, or "service-extension" (though that's kind of long and redundant).

                               

                              And the following artifactIds for the forthcoming #2:

                               

                              • org.jboss.arquillian.container:arquillian-embedded-spring-3
                              • org.jboss.arquillian.container:arquillian-embedded-spring-2.5

                               

                              I've deviated slightly from other containers by putting the management type (embedded) in front of the vendor (spring) and version (3 or 2.5). I think that reads better than the alternative:

                               

                              • org.jboss.arquillian.container:arquillian-spring-embedded-3
                              • org.jboss.arquillian.container:arquillian-spring-embedded-2.5

                               

                              I'm open to discussing any of these suggestions. The goal is to figure out what's most intuitative for users so that they just get it.

                              • 12. Re: Towards Spring Test Enricher Milesone One
                                jmnarloch

                                Dan Allen wrote:

                                 

                                I see your delimma about an exception in the resolution chain. This could be a good issue to bring up with Karel since they are in the midst of a design review for ShrinkWrap Resolvers.

                                 

                                You have another interesting use case as well. I think ShrinkWrap Resolvers should accept an optional version and deal with it internally. I see what you are shooting for. You want to allow the version from the project's pom to be honored, but if a version isn't declared there, then you want to use the explicit version. This really is a fantastic use case to raise to Karel & the team.

                                I'm actually going to bring this up, maybe it will result in some nice and simple solution.

                                 

                                 

                                ...for now, I think it's probably fine just to leave it how it was but implement the two exclusion approaches I suggested (a: let snowdrop resolve the spring version or b: exclude org.springframework:* when resolving the snowdrop artifact).

                                 

                                I will go for dependency exclusion, the Snowdrop is as well packaged with extension for Spring Framework 3.x so letting to resolve the dependencies by Snowdrop will end with runtime error, also it would be better to have consistent behaviour between extension targeted for Spring 2.5.x and 3.x.

                                • 13. Re: Towards Spring Test Enricher Milesone One
                                  jmnarloch

                                  To quickly answer You question.

                                  Dan Allen wrote:

                                   

                                  Since you are nearing a first preview release, I'd like to talk about naming. We are heading into some new territory with the Spring extension as far as terminology goes and it's important to get this right.

                                   

                                  First, some general naming requests:

                                   

                                  1. Relocate the @Spring*Configuration annotations to one of these packages (in preference order):

                                  • org.jboss.arquillian.spring.api.annotation (consistent with Drone)
                                  • org.jboss.arquillian.spring.test.api (consistent with Core)
                                  • org.jboss.arquillian.spring.test.annotation (merge the two concepts)

                                  (I'm open to ideas here).

                                  I would go with 1 or 3, although org.jboss.arquillian.spring.test.annotation is tempting.

                                   

                                  2. Rename *Consts classes

                                  • rename SpringExtensionConsts to SpringExtensionConstants
                                  • rename Spring3ExtensionConsts to SpringExtensionConstants_3
                                  • rename Spring25ExtensionConsts to SpringExtensionConstants_2_5

                                  Will be done today.

                                   

                                  3. Should we use the term extension in the root package name: org.jboss.arquillian.extension.spring? Drone doesn't follow this convention, but it would be more consistent.

                                   

                                  For example the Seam2 is defined as:

                                   

                                    <groupId>org.jboss.arquillian.extension</groupId>

                                    <artifactId>arquillian-seam2</artifactId>

                                   

                                  As I mentioned earlier, the Spring extension is the first of it's kind. It will provide:

                                   

                                  1. a packager/enricher, which I refer to as either a "service" or a "deployer"
                                  2. an embedded runtime, which I refer to as an "embedded service container"

                                   

                                  This leads me to suggest the following artifactId for #1:

                                   

                                  • org.jboss.arquillian.extension:arquillian-deployer-spring-3 (currently org.jboss.arquillian.extension:arquillian-spring-3)
                                  • org.jboss.arquillian.extension:arquillian-deployer-spring-2.5 (currently org.jboss.arquillian.extension:arquillian-spring-3)

                                   

                                  I'm not sure "deployer" is the right word here. Another possibility is "service", because it's as though you are installing the Spring service into the container. I guess "subsystem" would work as well, or "service-extension" (though that's kind of long and redundant).

                                   

                                  In my opinion the most accurate term would be testenricher, but the "service" works for me.

                                  • 14. Re: Towards Spring Test Enricher Milesone One
                                    jmnarloch

                                    There is one more final thing.

                                     

                                    Dan may I ask You to explain more detaily the concept of "embedded service container". In the beginning I'd thought that I understand it corectly, but now I have doubts. I had seen the weld embedded container but Spring IOC in the contrary CDI does not depends on any services provided by the container.

                                    1 2 Previous Next