1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.resourceloader.jcr;
35
36 import static info.magnolia.repository.RepositoryConstants.WEBSITE;
37 import static info.magnolia.resourceloader.ResourceOriginChange.Type.*;
38 import static info.magnolia.resourceloader.ResourceOriginChangeMatcher.resourceChange;
39 import static info.magnolia.resourceloader.jcr.JcrResourceOrigin.*;
40 import static org.junit.Assert.*;
41 import static org.mockito.Matchers.argThat;
42 import static org.mockito.Mockito.*;
43
44 import info.magnolia.context.MgnlContext;
45 import info.magnolia.context.SystemContext;
46 import info.magnolia.jcr.util.NodeTypes;
47 import info.magnolia.jcr.util.NodeUtil;
48 import info.magnolia.jcr.wrapper.DelegateSessionWrapper;
49 import info.magnolia.resourceloader.ResourceChangeHandler;
50 import info.magnolia.resourceloader.ResourceOriginChange;
51 import info.magnolia.test.RepositoryTestCase;
52 import info.magnolia.test.TestUtil;
53
54 import javax.jcr.Node;
55 import javax.jcr.Session;
56 import javax.jcr.nodetype.NodeType;
57 import javax.jcr.observation.EventListenerIterator;
58 import javax.jcr.observation.ObservationManager;
59 import javax.jcr.version.VersionManager;
60
61 import org.junit.After;
62 import org.junit.Before;
63 import org.junit.BeforeClass;
64 import org.junit.Test;
65
66
67
68
69 public class JcrResourceOriginRepositoryTest extends RepositoryTestCase {
70
71 private static final int TIMEOUT = 2000;
72
73 private Session session;
74 private JcrResourceOrigin jcrOrigin;
75
76 @BeforeClass
77 public static void shuntSlf4jSimpleLoggerForJackrabbit() {
78 TestUtil.shuntLogFor("org.apache.jackrabbit");
79 TestUtil.shuntLogFor(info.magnolia.jackrabbit.ProviderImpl.class);
80 }
81
82 @Override
83 @Before
84 public void setUp() throws Exception {
85 super.setUp();
86 final SystemContext ctx = (SystemContext) MgnlContext.getInstance();
87
88 this.session = ctx.getJCRSession(RESOURCES_WORKSPACE);
89 this.jcrOrigin = new JcrResourceOrigin(() -> ctx, "jcr");
90 }
91
92 @Override
93 @After
94 public void tearDown() throws Exception {
95 ObservationManager observationManager = session.getWorkspace().getObservationManager();
96 EventListenerIterator eventListeners = observationManager.getRegisteredEventListeners();
97 while (eventListeners.hasNext()) {
98 observationManager.removeEventListener(eventListeners.nextEventListener());
99 }
100 super.tearDown();
101 }
102
103 @Override
104 protected String getRepositoryConfigFileName() {
105 return "test-resource-repositories.xml";
106 }
107
108 @Test
109 public void communicatesFileResourceAddition() throws Exception {
110
111
112 final ResourceChangeHandler resourceChangeHandler = mock(ResourceChangeHandler.class);
113 jcrOrigin.registerResourceChangeHandler(resourceChangeHandler);
114
115
116 NodeUtil.createPath(session.getRootNode(), "foo/dialogs/bar.yaml", NodeTypes.ContentNode.NAME, true);
117
118
119 verify(resourceChangeHandler, timeout(TIMEOUT)).onResourceChanged(argThat(resourceChange().inOrigin(jcrOrigin).ofType(ADDED).at("/foo/dialogs/bar.yaml")));
120 }
121
122 @Test
123 public void communicatesFileResourceModification() throws Exception {
124
125
126 final Node barFileNode = NodeUtil.createPath(session.getRootNode(), "foo/dialogs/bar.yaml", NodeTypes.ContentNode.NAME, true);
127
128
129 final ResourceChangeHandler resourceChangeHandler = mock(ResourceChangeHandler.class);
130 jcrOrigin.registerResourceChangeHandler(resourceChangeHandler);
131
132
133 barFileNode.setProperty("qux", "quux");
134 session.save();
135
136
137 verify(resourceChangeHandler, timeout(TIMEOUT)).onResourceChanged(argThat(resourceChange().inOrigin(jcrOrigin).ofType(MODIFIED).at("/foo/dialogs/bar.yaml")));
138
139 assertNotEquals("Original session is released", session, MgnlContext.getJCRSession(RESOURCES_WORKSPACE));
140 }
141
142 @Test
143 public void communicatesFileResourceDeletion() throws Exception {
144
145
146 final Node barFileNode = NodeUtil.createPath(session.getRootNode(), "foo/dialogs/bar.yaml", NodeTypes.ContentNode.NAME, true);
147
148
149 final ResourceChangeHandler resourceChangeHandler = mock(ResourceChangeHandler.class);
150 jcrOrigin.registerResourceChangeHandler(resourceChangeHandler);
151
152
153 barFileNode.remove();
154 session.save();
155
156
157 verify(resourceChangeHandler, timeout(TIMEOUT)).onResourceChanged(argThat(resourceChange().inOrigin(jcrOrigin).ofType(REMOVED).at("/foo/dialogs/bar.yaml")));
158
159 assertNotEquals("Original session is released", session, MgnlContext.getJCRSession(RESOURCES_WORKSPACE));
160 }
161
162 @Test
163 public void communicatesResourceFolderAdditionWithContents() throws Exception {
164
165
166 final ResourceChangeHandler resourceChangeHandler = mock(ResourceChangeHandler.class);
167 jcrOrigin.registerResourceChangeHandler(resourceChangeHandler);
168
169
170 final Node fooDialogs = NodeUtil.createPath(session.getRootNode(), "foo/dialogs", NodeTypes.Folder.NAME);
171 NodeUtil.createPath(fooDialogs, "bar.yaml", NodeTypes.ContentNode.NAME);
172 NodeUtil.createPath(fooDialogs, "qux.yaml", NodeTypes.ContentNode.NAME);
173 session.save();
174
175
176 verify(resourceChangeHandler, timeout(TIMEOUT)).onResourceChanged(argThat(resourceChange().inOrigin(jcrOrigin).ofType(ADDED).at("/foo/dialogs")));
177 verify(resourceChangeHandler, timeout(TIMEOUT)).onResourceChanged(argThat(resourceChange().inOrigin(jcrOrigin).ofType(ADDED).at("/foo/dialogs/bar.yaml")));
178 verify(resourceChangeHandler, timeout(TIMEOUT)).onResourceChanged(argThat(resourceChange().inOrigin(jcrOrigin).ofType(ADDED).at("/foo/dialogs/bar.yaml")));
179 }
180
181 @Test
182 public void communicatesResourceFolderDeletionWithContents() throws Exception {
183
184
185 final Node fooDialogs = NodeUtil.createPath(session.getRootNode(), "foo/dialogs", NodeTypes.Folder.NAME, true);
186 NodeUtil.createPath(fooDialogs, "bar.yaml", NodeTypes.ContentNode.NAME, true);
187 NodeUtil.createPath(fooDialogs, "qux.yaml", NodeTypes.ContentNode.NAME, true);
188
189
190 final ResourceChangeHandler resourceChangeHandler = mock(ResourceChangeHandler.class);
191 jcrOrigin.registerResourceChangeHandler(resourceChangeHandler);
192
193
194 fooDialogs.remove();
195 session.save();
196
197
198 verify(resourceChangeHandler, timeout(TIMEOUT)).onResourceChanged(argThat(resourceChange().inOrigin(jcrOrigin).ofType(REMOVED).at("/foo/dialogs")));
199 verify(resourceChangeHandler, timeout(TIMEOUT)).onResourceChanged(argThat(resourceChange().inOrigin(jcrOrigin).ofType(REMOVED).at("/foo/dialogs/bar.yaml")));
200 verify(resourceChangeHandler, timeout(TIMEOUT)).onResourceChanged(argThat(resourceChange().inOrigin(jcrOrigin).ofType(REMOVED).at("/foo/dialogs/bar.yaml")));
201 }
202
203 @Test
204 public void bypassSetToTrueTreatedAsResourceRemoval() throws Exception {
205
206
207 final Node barFileNode = NodeUtil.createPath(session.getRootNode(), "foo/dialogs/bar.yaml", NodeTypes.ContentNode.NAME);
208 final Node bazFileNode = NodeUtil.createPath(session.getRootNode(), "foo/dialogs/baz.yaml", NodeTypes.ContentNode.NAME);
209 barFileNode.setProperty("bypass", false);
210 session.save();
211
212
213 final ResourceChangeHandler resourceChangeHandler = mock(ResourceChangeHandler.class);
214 jcrOrigin.registerResourceChangeHandler(resourceChangeHandler);
215
216
217 bazFileNode.setProperty("bypass", true);
218
219 barFileNode.setProperty("bypass", true);
220 session.save();
221
222
223 verify(resourceChangeHandler, timeout(TIMEOUT)).onResourceChanged(argThat(resourceChange().inOrigin(jcrOrigin).ofType(REMOVED).at("/foo/dialogs/bar.yaml")));
224 verify(resourceChangeHandler, timeout(TIMEOUT)).onResourceChanged(argThat(resourceChange().inOrigin(jcrOrigin).ofType(REMOVED).at("/foo/dialogs/baz.yaml")));
225
226 assertNotEquals("Original session is released", session, MgnlContext.getJCRSession(RESOURCES_WORKSPACE));
227 }
228
229 @Test
230 public void bypassSetToFalseTreatedAsResourceAddition() throws Exception {
231
232
233 final Node barFileNode = NodeUtil.createPath(session.getRootNode(), "foo/dialogs/bar.yaml", NodeTypes.ContentNode.NAME);
234 barFileNode.setProperty("bypass", true);
235 session.save();
236
237
238 final ResourceChangeHandler resourceChangeHandler = mock(ResourceChangeHandler.class);
239 jcrOrigin.registerResourceChangeHandler(resourceChangeHandler);
240
241 barFileNode.setProperty("bypass", false);
242 session.save();
243
244
245 verify(resourceChangeHandler, timeout(TIMEOUT)).onResourceChanged(argThat(resourceChange().inOrigin(jcrOrigin).ofType(ADDED).at("/foo/dialogs/bar.yaml")));
246 }
247
248 @Test
249 public void ignoreChangesWhenResourceIsBypassed() throws Exception {
250
251 Node folder = NodeUtil.createPath(session.getRootNode(), "myModule/dialogs", NodeTypes.Folder.NAME);
252 Node file = folder.addNode("panda.yaml", NodeTypes.Content.NAME);
253 file.setProperty(BYPASS_PROPERTY, true);
254 session.save();
255
256
257 final ResourceChangeHandler resourceChangeHandler = mock(ResourceChangeHandler.class);
258 jcrOrigin.registerResourceChangeHandler(resourceChangeHandler);
259
260
261 file.setProperty("text", "<DUMMY CONTENT>");
262 session.save();
263
264
265 verify(resourceChangeHandler, after(TIMEOUT).never()).onResourceChanged(anyObject());
266 }
267
268 @Test
269 public void ignoreChangesOnSharedSystemNodesWhenWatchingResourcesRoot() throws Exception {
270
271 final ResourceChangeHandler resourceChangeHandler = mock(ResourceChangeHandler.class);
272 jcrOrigin.registerResourceChangeHandler(resourceChangeHandler);
273
274
275 Session websiteSession = MgnlContext.getJCRSession(WEBSITE);
276 websiteSession.getRootNode().addNode("b", NodeTypes.Content.NAME);
277 websiteSession.save();
278 VersionManager versionManager = ((DelegateSessionWrapper) websiteSession).unwrap().getWorkspace().getVersionManager();
279
280
281 websiteSession.getNode("/b").addMixin(NodeType.MIX_VERSIONABLE);
282 websiteSession.save();
283 versionManager.checkin("/b");
284
285
286
287 verify(resourceChangeHandler, after(TIMEOUT).never()).onResourceChanged(any(ResourceOriginChange.class));
288 verifyZeroInteractions(resourceChangeHandler);
289 }
290 }