14 Replies Latest reply on Jul 17, 2010 1:10 PM by pmuir

    Deployment specification:

    jnorris10

      I've finished reading Dan's initial reference draft, and overall, things are looking great.  Nice work!

       

      I have one concern regarding specifying "mico-deployments", eg:

       

      @Deployment 
      public static JavaArchive createTestArchive() {
        return Archives.create("test.jar", JavaArchive.class)
          .addClass(NameOfClassUnderTest.class)
          .addManifestResource(new ByteArrayAsset(new byte[0]), Paths.create("beans.xml"))
      

       

      This concept is fantastic and well described/justified in the reference draft, however I am worried that in many common use cases, I'm going to want the "micro-deployment" to be defined exactly the same as the project's test classpath.  In these cases, it will be very onerous to maintain the same list in two places.  (Especially in real-world scenarios, the list of classes, resources and libraries can be fairly large).

       

      While the power to specify your own "micro-deployment" is tremendous and will be very valuable in many situations, I'm not sure this will be the common use case.  In my opinion a very common use-case will be:

       

      • Use everything on my test classpath as defined by my current maven project.  It is common for JEE6 technologies (ie: JPA, CDI, EJB, etc.) to allow you to override settings/configurations/active components etc. on the classpath and every maven project has a test classpath already defined for it.  Agreed, sometimes this can be classpath hell, but I can always drop down a level and specified my micro-deployment in a very detailed manor when it's warranted, but I think there are a lot of common cases where it won't be warranted. 

       

      Perhaps you are thinking of very fine grained tests which test individual components, but even in these cases, these individual components usually have lots of dependencies and maintaining the list of what's needed for each specific deployment seems like it will be unnecessarily hard (and duplicated).

       

      Thoughts?

        • 1. Re: Deployment specification:
          alrubinger

          Link to the design discussion about creating a @Deployment given a Maven artifact:

           

          Re: Arquillian Design Questions:

           

          S,

          ALR

          • 2. Re: Deployment specification:
            jnorris10

            Hi Andrew,

             

            Maybe I am missing something but that thread deals with things like this:

            JavaArchive archive = Maven2Archives.create("groupId","artifactId","classifier","type",JavaArchive.class);

             

            This is fine for referencing other maven dependencies, but not the current project.  One advantage of ShrinkWrap is it's ability to abstract the archive so it can be handed off to the AS without going through the normal build/assembly process.  I don't really want to refer to the current artifact in a local or remote repository since it's already built and assembled by that point (and hence very difficult to test quickly from IDE).

             

            Rather, what I am looking for is the ability to shrinkwrap the current maven test classpath contents (ie: src/{main,test}/{java,resources}, etc. for the reasons that I outlined above.

             

            -Jeremy

             

            PS. Sorry, I could have kept this on the other thread, but it seemed to be going in a different direction.

            • 3. Re: Deployment specification:
              jnorris10

              Hi Andrew,

               

              Perhaps this is exactly what you meant by this construct:

               

              @CurrentArtifact(classifier="jar")
              JavaArchive theThingImBuildingInThisProject;
              • 4. Re: Deployment specification:
                alrubinger

                jnorris10 wrote:

                 

                Hi Andrew,

                 

                Perhaps this is exactly what you meant by this construct:

                 

                @CurrentArtifact(classifier="jar")
                JavaArchive theThingImBuildingInThisProject;

                Yep, exactly.

                 

                Because really the "current project" is just a simple wrapper around "any project".  We need the stuff from Maven local repo or a known path; "current" just tells us which artifact.

                 

                S,

                ALR

                • 5. Re: Deployment specification:
                  jnorris10
                  Ok, great.  Sorry about the confusion.
                  • 6. Re: Deployment specification:
                    alrubinger

                    jnorris10 wrote:

                     

                    Ok, great.  Sorry about the confusion.

                    No apologies; keep the ideas flowing.

                     

                    S,

                    ALR

                    • 7. Re: Deployment specification:
                      aslak

                      I started looking into the different Maven integration options the other day and i'm in need of some community feedback..

                       

                      #1 - Import 'current' project based on pom.xml

                      e.g.:
                      @CurrentProject
                      Archive<?> archive;
                       
                       
                      WebArchive war = MavenImporter.importProject(
                         WebArchive.class,
                         "pom.xml",
                         Scope.TEST);
                      
                      
                      • Jar project
                        • we can import target class folders
                        • but can't import libraries, JavaArchive is not a Library container
                       
                         Might as well just do ExplodedImport.import("target/classes").as(JavaArchive.class) manually.
                         We could parse pom to auto find target folders....
                       
                      • War project
                        • we can import target class folders
                        • we can import libraries from given pom in given scope
                          • if based on Test scope we need to exclude artifacts like arquillian/shrinkwrap and any other extension(packaged up else where). These could be placed in provided scope as well..
                      • Ear project
                        • we don't know how to build the Enterprise archive structure unless we duplicate the Maven ear plugin.
                          • e.g. what is a Jar? Library of Module ?
                       
                      In all cases we need to duplicate a lot of the functionality of the jar/war/rar/ear packager plugins to make it predictable in the fashion Maven does it (e.g. packager settings, filtering, includes/excludes, etc.). Or we can execute the packager plugins directly via Maven for you, but in that case you might as well create a separate test project for the Artifact and just import it there(see next option).
                        
                      #2 - Maven based artifact import:
                      • To import the output of your own module, you need to move the test case execution into the integration-test lifecycle so that the package is done before the tests run.
                        • Or have a separate Test project for the Artifact. (see next option)
                       
                         At this point, the Package is all ready created and known, so no special Maven integration is needed.
                         You can just do ZipImporter.import("target/mywar.war").as(WebArchive.class);
                         We could parse pom to auto find finalName/version etc.
                       
                      #3 - Maven Library import:
                      e.g.:
                      ShrinkWrap.create(WebArchive.class)
                         .addLibraries(Maven.resolve("group:artifact:classifier"));
                      
                      

                      • Resolve all dependencies of a specific artifact
                       
                       
                      My conclusion so far is; Without reimplementing Mavens Packagers, the only sensible maven integration we can do is #3 ?
                      I'm sure you guys have a bunch of comments.. so.. fire away..
                       
                      • 8. Re: Deployment specification:
                        jnorris10

                        In my opinion, #2 works against one of the big benefits of Arquillian, namely that you don't have to execute the external maven lifecycle to run your tests (allowing you to work faster in the IDE, utilize continuous compilation, etc.)  #3 is useful but it doesn't solve the entire problem (ie: of manually listing all the local classes and resources).

                         

                        I think #1 is the right direction.  However, I understand the challenges you raise. 

                         

                        Can we use the maven embedder and construct the artifact using maven at (Arquillian/Shrinkwrap) test runtime?  Overall, this is a little bit strange because a full maven build will end up constructing the artifact multiple times (once for the main, external lifecycle, and then once for each @CurrentProject archive during testing).  However, I think this is the price we have to pay if we want maven archive support and quick round-trip development in the IDE.

                         

                        A question may be raised: "Won't that make the test execution 'slow' in the IDE?"  It will be slower than a manual Archives.create(...), however, the cost of integrating with Maven is bound by the time it takes Maven to perform it's actions.  Trying to work around Maven and do a smaller, lightweight implementation of it's packaging phase will be a maintenance burden as there are lots of things to consider (settings, filtering, includes/excludes, etc).  Furthermore, the maven embedder may be plenty fast enough.  It's very fast in m2eclipse.

                         

                        Thoughts?

                        • 9. Re: Deployment specification:
                          aslak

                          Created a little test case that pulls up 10 of the ShrinkWrap poms to see some speeds..

                           

                          [number of resolved artifacts] [time in ms] pom file used (working dir is extension-maven/)

                           

                          [@Before] 619  <-- bootstrap Maven 3 Container
                          [23] [807] pom.xml  <--warm up
                          [0] [13] ../pom.xml
                          [10] [199] ../extension-classloader/pom.xml
                          [60] [1174] ../extension-vdf/pom.xml
                          [9] [23] ../extension-vfs3/pom.xml
                          [39] [302] ../extension-openejb/pom.xml
                          [15] [115] ../extension-glassfish/pom.xml
                          [1] [14] ../api/pom.xml
                          [4] [25] ../impl-base/pom.xml
                          [1] [13] ../spi/pom.xml
                          
                          
                          

                           

                          http://arquillian.pastebin.com/Np9xvNbW

                           

                           

                          ps: this is just Artifact resolution, not packaging.

                          • 10. Re: Deployment specification:
                            pmuir

                            Jeremy Norris wrote:

                             

                            I think #1 is the right direction.  However, I understand the challenges you raise. 

                             

                            Can we use the maven embedder and construct the artifact using maven at (Arquillian/Shrinkwrap) test runtime?  Overall, this is a little bit strange because a full maven build will end up constructing the artifact multiple times (once for the main, external lifecycle, and then once for each @CurrentProject archive during testing).  However, I think this is the price we have to pay if we want maven archive support and quick round-trip development in the IDE.

                            This is the way I envisaged this working - we call out to the maven embedder to do the actual build, and then import that structure. I think trying to mimic Maven would be very ill advised - firstly we shouldn't reinvent the wheel, or believe that we can make a better wheel. Secondly, we would struggle to reproduce all the bugs in Maven so that we got an identical end user experience.

                             

                            The overhead of doing this may be the problem of course, but I do wonder if there is some way of "picking up" the existing build if you run using Maven, rather than from the IDE? (No idea, just think we could explore this). Alternatively, we could have a plugin for the Maven build that generates the metadata, stores it to disk, then Arquillian reads it - yes, this is a bit more manual, but you don't often have to regenerate this kind of info.

                            • 11. Re: Deployment specification:
                              pmuir

                              What is the @CurrentProject annotation for?

                              • 12. Re: Deployment specification:
                                aslak

                                Pete Muir wrote:

                                 

                                What is the @CurrentProject annotation for?

                                Just a conceptual drawing Annotation. It will probably be more like:

                                 

                                 

                                @Deployment
                                public static Archive<?> createDeployment() 
                                {
                                  return Maven.generateProjectArtifact("pom.xml");
                                }
                                

                                 

                                 

                                But we might come into a little dependency loop here tho. I'm not sure we can execute just the packaging, since it 'depends' on the previous steps like compile and test.. So when we execute package from within a test it needs to run the test to package and so on.. I guess we have to force a -DskipTests or -Dmaven.skip.test=true

                                 

                                 

                                • 13. Re: Deployment specification:
                                  jnorris10

                                  Pete Muir wrote:

                                   

                                  This is the way I envisaged this working - we call out to the maven embedder to do the actual build, and then import that structure. I think trying to mimic Maven would be very ill advised - firstly we shouldn't reinvent the wheel, or believe that we can make a better wheel. Secondly, we would struggle to reproduce all the bugs in Maven so that we got an identical end user experience.

                                  I absolutely agree.

                                  • 14. Re: Deployment specification:
                                    pmuir

                                    Aslak Knutsen wrote:


                                    @Deployment
                                    public static Archive<?> createDeployment() 
                                    {
                                      return Maven.generateProjectArtifact("pom.xml");
                                    }
                                    

                                     

                                     

                                    But we might come into a little dependency loop here tho. I'm not sure we can execute just the packaging, since it 'depends' on the previous steps like compile and test.. So when we execute package from within a test it needs to run the test to package and so on.. I guess we have to force a -DskipTests or -Dmaven.skip.test=true

                                    That looks a lot better :-)