3 Replies Latest reply on Jul 17, 2010 12:57 AM by mazi

    SeamTest and Conversations

    cmoerz.seam.ny-central.org

      Hi everyone,


      I've run into trouble trying to get a more complex SeamTest to run. I want to test a seam application using inner FacesRequest objects. Those should be logging in, going to a page where a couple of database entries are listed (via a DataModel and a h:dataTable), select one of the entries and then edit that item and last but not least press the save button.


      Everything works fine up to the point where the item is about to be edited; that's where a conversation is started (via a Begin annotated function) and everything goes wacko. The initial FacesRequest to the edit page, that starts the conversation works out fine, but when it comes to pressing the save button (which is the next FacesRequest), it fails. First of all - yes, I do hand further the conversation id, but it seems like that conversation got stomped or something because in debug mode I saw that Manager.instance()... seems to believe that there's no conversation running anymore and the Component that's getting called/instantiated by the FacesRequest.invokeAction method has a different hashCode and therefore is another object than the one before. Theoretically this must not happen, because the component that handles that editing process is a stateful bean, so for the same request it must be the same component instance.


      Is there anyone who can give me good example how this whole SeamTest thing works with a more complex test that goes over a couple of pages, starts and also ends a conversation? All the tests in the example directory are very brief and never ever have a conversation that goes over several FacesRequests. Is it possible that FacesRequest doesn't support a long running conversation over several requests?


      Let me show you some of my code I tried: That's an example, but in this case I tried to press the cancel button, but even that fails with the exception that supposedly no transaction is running (duh, that's because I'm suddenly working on the wrong component...)


      Here's the test:


      public class EditCompanyTest extends HermesTest {
      @Test
           public void testShort() throws Exception {
                String id = login();
                
                new FacesRequest( "/company.seam" ){
                     /*@SuppressWarnings("unchecked")
                     @Override
                     protected void renderResponse() {
                          List<Company>     listCompanies = (List<Company>) getValue("#{companyList.companies}");
      
                          assert null != listCompanies;
                          assert listCompanies.size() > 0;
                          assert !Manager.instance().isLongRunningConversation();
                     }*/
      
                }.run();
                
                new FacesRequest( "/company.seam") {
                     @Override
                     protected void updateModelValues() {
                          Company          company;
                          List<Company>     listCompanies = (List<Company>) getValue("#{companyList.companies}");
                          
                          assert null != listCompanies;
                          
                          company = listCompanies.get( 0 );
                          
                          assert null != company;
                          
                          setValue( "#{company}", company );
                     }
                     
                     @Override
                     protected void invokeApplication() {
                          invokeAction( "#{companyList.selectCompany(company)}" );
                          
                          assert null != getValue( "#{companyList.selCompany}" );
                     }
                     
                     @Override
                     protected void renderResponse() {
                          
                     }
                }.run();
                
                id = new FacesRequest( "/company/view.seam" ) {
                     
                     @Override
                     protected void invokeApplication() {
                          invokeAction( "#{companyEdit.editCompany( selCompany )}" );
                     }
                     
                     @Override
                     protected void renderResponse() {
                          assert Manager.instance().isLongRunningConversation();
                     }
                }.run();
      



      Up to here, everything works fine - id is retuned as 10.


                
                new FacesRequest( "/company/edit.seam", id ) {
                     
                     @Override
                     protected void updateModelValues() throws Exception {
                          CompanyEdit          cmpEdit = (CompanyEdit) getValue( "#{companyEdit}" );
                          
                          assert Manager.instance().isLongRunningConversation();
                          
                          setValue( "#{companyEdit.companyObj.name}", "Renamed Company" );
                          setValue( "#{companyEdit.companyObj.address.street}", "Street value" );
                     }
                     
                     @Override
                     protected void invokeApplication() {
                          invokeAction( "#{companyEdit.cancel}" );
                     }
                }.run();
      



      And now it happened: when the FacesRequest wants to invoke cancel, it fails with a nice, huge exception.


                
                new FacesRequest( "/company/view.seam" ) {
                     
                     @Override
                     protected void renderResponse() {
                          Company          company;
                          
                          assert !Manager.instance().isLongRunningConversation();
                          
                          company = (Company) getValue( "#{companyList.selCompany}" );
                          assert company.getName().equals( "Test Company AG" );
                     }
                }.run();
           }
      }
      



      If anyone can give me some input or point me to a more in-depth resource for SeamTest/FacesRequest and Seam testing in general - or even better, point me at some mistake I made, I'd be very thankful.


      By the way - can anyone please explain to me, what the difference is between FacesRequest and NonFacesRequest? What's the difference between those two? I mean, I understand that FacesRequest emulates the web access to a faces page, but what's the NonFacesRequest good for?


      thanks in advance


      chris

        • 1. Re: SeamTest and Conversations
          cmoerz.seam.ny-central.org

          Don't know if this helps, but that's what I get when cancel is about to invoked:


          WARN  [org.jboss.seam.Component] Exception calling component @Destroy method: entityManager
          java.lang.IllegalStateException: attempting to destroy the persistence context while an active transaction exists (try installing <transaction:ejb-transaction/>)
               at org.jboss.seam.persistence.ManagedPersistenceContext.close(ManagedPersistenceContext.java:214)
               at org.jboss.seam.persistence.ManagedPersistenceContext.destroy(ManagedPersistenceContext.java:177)
               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:585)
               at org.jboss.seam.util.Reflections.invoke(Reflections.java:22)
               at org.jboss.seam.util.Reflections.invokeAndWrap(Reflections.java:144)
               at org.jboss.seam.Component.callComponentMethod(Component.java:2211)
               at org.jboss.seam.Component.callDestroyMethod(Component.java:2142)
               at org.jboss.seam.Component.destroy(Component.java:1436)
               at org.jboss.seam.contexts.Contexts.destroy(Contexts.java:251)
               at org.jboss.seam.contexts.Contexts.destroyConversationContext(Contexts.java:413)
               at org.jboss.seam.contexts.Lifecycle.endSession(Lifecycle.java:258)
               at org.jboss.seam.contexts.ServletLifecycle.endSession(ServletLifecycle.java:146)
               at org.jboss.seam.mock.AbstractSeamTest.end(AbstractSeamTest.java:903)
               at org.jboss.seam.mock.SeamTest.end(SeamTest.java:37)
               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:585)
               at org.testng.internal.MethodHelper.invokeMethod(MethodHelper.java:580)
               at org.testng.internal.Invoker.invokeConfigurationMethod(Invoker.java:398)
               at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:145)
               at org.testng.internal.Invoker.invokeMethod(Invoker.java:531)
               at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:617)
               at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:885)
               at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:126)
               at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:110)
               at org.testng.TestRunner.runWorkers(TestRunner.java:712)
               at org.testng.TestRunner.privateRun(TestRunner.java:582)
               at org.testng.TestRunner.run(TestRunner.java:477)
               at org.testng.SuiteRunner.runTest(SuiteRunner.java:324)
               at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:319)
               at org.testng.SuiteRunner.privateRun(SuiteRunner.java:292)
               at org.testng.SuiteRunner.run(SuiteRunner.java:198)
               at org.testng.TestNG.createAndRunSuiteRunners(TestNG.java:823)
               at org.testng.TestNG.runSuitesLocally(TestNG.java:790)
               at org.testng.TestNG.run(TestNG.java:708)
               at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:73)
               at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:124)
          

          • 2. Re: SeamTest and Conversations
            mazi

            Hi Chris,


            I have a very similar problem: a SeamTest with severa consecutive requests: first login, then several requests in a long-running conversation. The test fails with the same exception. I'm using Seam 2.2.1.CR1.


            Did you solve this problem? Do you remember how?


            Also note the assert false in the second FacesRequest's renderResponse() -- renderResponse() doesn't get called. I suspect there is an exception after the invokeApplication(), but there is nothing in the log. The test fails somewhere in the third FacesRequest() (if I remove it, the test passes, even though it should fail because of the assert false).


            Thanks for any help,
            Matija




            public class ReservationActionTest extends ReservationTestSupport {
                private static final SimpleDateFormat DATEFORMAT = new SimpleDateFormat("d.M.y");
            
                @Test
                public void testReservationsAction() throws Exception {
                    // gp login
                    new FacesRequest("/login.seam") {
                        @Override
                        protected void updateModelValues() throws Exception {
                            assert !isSessionInvalid();
                            setValue("#{credentials.username}", "mazi");
                            setValue("#{credentials.password}", "mazi");
                        }
                        @Override
                        protected void invokeApplication() {
                            invokeAction("identity.login");
                        }
                        @Override
                        protected void renderResponse() {
                            assert !isLongRunningConversation();
                            assert getValue("#{identity.hasRole('GeneralPractitioner')}").equals(true);
                            assert getValue("#{identity.hasRole('NoSuchRole')}").equals(false);
                        }
                    }.run();
            
                    // find patient
                    String conversationId = new FacesRequest("/gp/find-patient.seam") {
                        @Override
                        protected void updateModelValues() throws Exception {
                            setValue("#{reservations.patient.id}", 80705000018L);
                        }
                        @Override
                        protected void invokeApplication() {
                            invokeAction("#{reservations.findPatient}");
            
                            // todo: renderResponse() doesn't get called (some exception after invokeApplication that doesn't get logged?)
                            // so put assertions here
                            CentralPersistenceInit pi = (CentralPersistenceInit) getValue("#{centralPersistenceInit}");
                            assert getValue("#{reservations.patient.id}").equals(CentralPersistenceInit.PATIENT_MAZI_ID) : "Wrong patient, got " + getValue("#{reservations.patient}");
                            assert getValue("#{reservations.patient.fullName}").equals(pi.getPatientMM().getFullName()) : "Wrong patient, got " + getValue("#{reservations.patient}");
                            assert isLongRunningConversation();
                        }
            
                        @Override
                        protected void renderResponse() throws Exception {
                            assert false : "renderResponse got called! How did you manage to fix this??";
                        }
                    }.run();
            
                    // update patient data
                    conversationId = new FacesRequest("/gp/edit-patient.seam", conversationId) {
                        @Override
                        protected void updateModelValues() throws Exception {
                            assert getValue("#{reservations.patient.id}") != null : "Patient id was null";
                            setValue("#{reservations.patient.contrastAllergies}", "NE");
                        }
                        @Override
                        protected void invokeApplication() {
                            invokeAction("reservations.savePatient");
                            assert isLongRunningConversation();
                        }
                    }.run();
                }
            }
            



            • 3. Re: SeamTest and Conversations
              mazi

              What I did then was I used invokeMethod instead of invokeAction. It seems that calling setOutcome (inside invokeAction or on its own), even though it itself works, later causes some problems that I don't understand.