001    // Copyright 2005 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    //     http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package org.apache.tapestry.record;
016    
017    import static org.easymock.EasyMock.checkOrder;
018    import static org.easymock.EasyMock.expect;
019    
020    import java.util.ArrayList;
021    import java.util.Collection;
022    import java.util.Collections;
023    
024    import org.apache.hivemind.ApplicationRuntimeException;
025    import org.apache.hivemind.ErrorLog;
026    import org.apache.hivemind.Location;
027    import org.apache.hivemind.Resource;
028    import org.apache.tapestry.BaseComponentTestCase;
029    import org.apache.tapestry.IComponent;
030    import org.apache.tapestry.IPage;
031    import org.apache.tapestry.event.ObservedChangeEvent;
032    import org.apache.tapestry.spec.IComponentSpecification;
033    import org.apache.tapestry.spec.IPropertySpecification;
034    import org.apache.tapestry.test.Creator;
035    import org.testng.annotations.Test;
036    
037    /**
038     * Tests for {@link org.apache.tapestry.record.PageRecorderImpl}.
039     * 
040     * @author Howard M. Lewis Ship
041     * @since 4.0
042     */
043    @Test
044    public class TestPageRecorder extends BaseComponentTestCase
045    {
046        private ErrorLog newErrorLog()
047        {
048            return newMock(ErrorLog.class);
049        }
050    
051        public void testGetChanges()
052        {
053            ErrorLog log = newErrorLog();
054            
055            PropertyPersistenceStrategySource source = newMock(PropertyPersistenceStrategySource.class);
056    
057            Collection expected = new ArrayList();
058    
059            expect(source.getAllStoredChanges("Foo")).andReturn(expected);
060    
061            replay();
062    
063            PageRecorderImpl pr = new PageRecorderImpl("Foo", source, log);
064    
065            Collection actual = pr.getChanges();
066    
067            assertSame(expected, actual);
068    
069            verify();
070        }
071    
072        private IComponentSpecification newSpec(String propertyName, String persistence)
073        {
074            IComponentSpecification spec = newSpec();
075            
076            IPropertySpecification ps = newMock(IPropertySpecification.class);
077            checkOrder(ps, false);
078            
079            expect(spec.getPropertySpecification(propertyName)).andReturn(ps);
080    
081            expect(ps.getPersistence()).andReturn(persistence);
082    
083            return spec;
084        }
085    
086        public void testObserveChange()
087        {
088            ErrorLog log = newErrorLog();
089            
090            IPage page = newPage();
091    
092            IComponentSpecification spec = newSpec("foobar", "session");
093            
094            expect(page.getSpecification()).andReturn(spec);
095    
096            expect(page.getIdPath()).andReturn(null);
097    
098            PropertyPersistenceStrategySource source = newMock(PropertyPersistenceStrategySource.class);
099    
100            PropertyPersistenceStrategy strategy = newMock(PropertyPersistenceStrategy.class);
101    
102            expect(source.getStrategy("session")).andReturn(strategy);
103    
104            Object newValue = new Object();
105    
106            strategy.store("Foo", null, "foobar", newValue);
107    
108            replay();
109    
110            PageRecorderImpl pr = new PageRecorderImpl("Foo", source, log);
111    
112            ObservedChangeEvent event = new ObservedChangeEvent(page, "foobar", newValue);
113    
114            pr.observeChange(event);
115    
116            verify();
117        }
118    
119        public void testUnknownStategy()
120        {
121            Location l = fabricateLocation(12);
122            Throwable inner = new ApplicationRuntimeException("Simulated error.");
123            ErrorLog log = newErrorLog();
124    
125            PropertyPersistenceStrategySource source = newMock(PropertyPersistenceStrategySource.class);
126    
127            IComponent component = newComponent();
128            
129            IComponentSpecification spec = newSpec();
130            
131            IPropertySpecification ps = newMock(IPropertySpecification.class);
132    
133            expect(component.getSpecification()).andReturn(spec);
134    
135            expect(spec.getPropertySpecification("zip")).andReturn(ps);
136    
137            expect(ps.getPersistence()).andReturn("unknown");
138    
139            expect(source.getStrategy("unknown")).andThrow(inner);
140    
141            expect(ps.getLocation()).andReturn(l);
142    
143            log.error("Simulated error.", l, inner);
144    
145            replay();
146    
147            PageRecorderImpl pr = new PageRecorderImpl("SomePage", source, log);
148    
149            assertNull(pr.findStrategy(component, "zip"));
150    
151            verify();
152        }
153    
154        public void testRollbackPageProperty()
155        {
156            ErrorLog log = newErrorLog();
157    
158            Creator creator = new Creator();
159    
160            PageFixture page = (PageFixture) creator.newInstance(PageFixture.class);
161    
162            PropertyPersistenceStrategySource source = newMock(PropertyPersistenceStrategySource.class);
163    
164            PropertyChange pc = new PropertyChangeImpl(null, "cartoonName", "Dexter's Laboratory");
165    
166            expect(source.getAllStoredChanges("MyPage")).andReturn(Collections.singletonList(pc));
167    
168            replay();
169    
170            PageRecorderImpl pr = new PageRecorderImpl("MyPage", source, log);
171    
172            pr.rollback(page);
173    
174            assertEquals("Dexter's Laboratory", page.getCartoonName());
175    
176            verify();
177        }
178    
179        public void testRollbackComponentProperty()
180        {
181            ErrorLog log = newErrorLog();
182            
183            IPage page = newPage();
184    
185            IComponent component = newMock(IComponent.class);
186    
187            PropertyPersistenceStrategySource source = newMock(PropertyPersistenceStrategySource.class);
188    
189            PropertyChange pc = new PropertyChangeImpl("fred.barney", "id", "ziff");
190    
191            expect(source.getAllStoredChanges("MyPage")).andReturn(Collections.singletonList(pc));
192    
193            expect(page.getNestedComponent("fred.barney")).andReturn(component);
194    
195            component.setId("ziff");
196    
197            replay();
198    
199            PageRecorderImpl pr = new PageRecorderImpl("MyPage", source, log);
200    
201            pr.rollback(page);
202    
203            verify();
204        }
205    
206        public void testChangeWhileLocked()
207        {
208            ErrorLog log = newErrorLog();
209            
210            IPage page = newPage();
211    
212            PropertyPersistenceStrategySource source = newMock(PropertyPersistenceStrategySource.class);
213    
214            expect(page.getExtendedId()).andReturn("MyPage");
215    
216            log
217                    .error(
218                            "Change to persistent property foobar of MyPage has been ignored."
219                                    + " Persistent properties may only be changed prior to the rendering of the response page.",
220                            null,
221                            null);
222    
223            replay();
224    
225            PageRecorderImpl pr = new PageRecorderImpl("MyPage", source, log);
226    
227            pr.commit();
228    
229            ObservedChangeEvent event = new ObservedChangeEvent(page, "foobar", new Object());
230    
231            pr.observeChange(event);
232    
233            verify();
234        }
235    
236        public void testChangeToNonSpecifiedProperty()
237        {
238            Resource r = newResource();
239            
240            ErrorLog log = newErrorLog();
241            
242            IPage page = newPage();
243            
244            IComponentSpecification spec = newSpec();
245    
246            PropertyPersistenceStrategySource source = newMock(PropertyPersistenceStrategySource.class);
247    
248            expect(page.getSpecification()).andReturn(spec);
249    
250            expect(spec.getPropertySpecification("foobar")).andReturn(null);
251    
252            expect(page.getExtendedId()).andReturn("TestPage");
253    
254            expect(page.getSpecification()).andReturn(spec);
255    
256            expect(spec.getSpecificationLocation()).andReturn(r);
257    
258            log.error(
259                    "A property change event for property foobar of TestPage was observed, "
260                            + "but no such property is identified in the specification (" + r + ").",
261                    null,
262                    null);
263    
264            replay();
265    
266            PageRecorderImpl pr = new PageRecorderImpl("TestPage", source, log);
267    
268            ObservedChangeEvent event = new ObservedChangeEvent(page, "foobar", new Object());
269    
270            pr.observeChange(event);
271    
272            verify();
273        }
274    }