/** * Copyright (C) 2015 Born Informatik AG (www.born.ch) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.wte4j.persistence; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.PersistenceException; import org.apache.commons.collections4.map.HashedMap; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.transaction.TransactionConfiguration; import org.springframework.transaction.annotation.Transactional; import org.wte4j.EmbeddedDataBaseConfig; import org.wte4j.FileStore; import org.wte4j.LockingException; import org.wte4j.MappingDetail; import org.wte4j.Template; import org.wte4j.TemplateQuery; import org.wte4j.User; import org.wte4j.WteModelService; import org.wte4j.impl.TemplateContextFactory; import org.wte4j.impl.WordTemplate; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = { EmbeddedDataBaseConfig.class }) @TransactionConfiguration(defaultRollback = true) @Transactional public class WordTemplateRepositoryTest { private static final long LOCKED_TEMPLATE = 2; private static final long UNLOCKED_TEMPLATE = 1; @PersistenceContext EntityManager entityManager; TemplateContextFactory contextFactory = mock(TemplateContextFactory.class); WteModelService modelService = mock(WteModelService.class); WordTemplateRepository repository; @Before public void initTest() throws Exception { repository = new WordTemplateRepository(entityManager, contextFactory); } @Test @Transactional public void testQueryTemplates() { TemplateQuery query = repository.queryTemplates(); List<Template<Object>> templates = query.list(); assertEquals(4, templates.size()); } @Test @Transactional public void testQueryWithEmptyResults() { TemplateQuery query = repository.queryTemplates(); List<Template<Object>> templates = query.language("xxx").list(); assertEquals(0, templates.size()); } @Test @Transactional public void getTemplate() { Template<?> template = repository.getTemplate("test1", "en"); assertNotNull(template); } @Test @Transactional public void getNonExistingTemplate() { Template<?> template = repository.getTemplate("XXXX", "XX"); assertNull(template); } @Test(expected = IllegalArgumentException.class) @Transactional public void getTemplateWithWrongInputType() { repository.getTemplate("test1", "en", Date.class); fail("Exception expected"); } @Test @Transactional public void locking() { WordTemplate<?> template = unlockedTemplate(); User lockingUser = new User("locking", "Locking User"); Template<?> locked = repository.lockForEdit(template, lockingUser); assertEquals(lockingUser, locked.getLockingUser()); assertTrue(isVersionIncontext(locked)); } @Test @Transactional public void lockingLockedTemplate() { WordTemplate<?> toLock = lockedTemplate(); User second = new User("second", "Second User"); try { repository.lockForEdit(toLock, second); fail(LockingException.class + " expected"); } catch (LockingException e) { assertTrue(isVersionIncontext(toLock)); } } @Test(expected = LockingException.class) @Transactional public void lockingTemplateParallel() { Template<?> template1 = unlockedTemplate(); Template<?> template2 = unlockedTemplate(); template1 = repository.lockForEdit(template1, new User("first", "First")); User second = new User("second", "Second User"); repository.lockForEdit(template2, second); fail(LockingException.class + " expected"); } @Test @Transactional public void lockingTwice() { Template<?> template = unlockedTemplate(); User user = new User("user", "User"); template = repository.lockForEdit(template, user); template = repository.lockForEdit(template, user); assertEquals(user, template.getLockingUser()); } @Test @Transactional public void unlock() { WordTemplate<?> template = lockedTemplate(); Template<?> unlocked = repository.unlock(template); assertNull(unlocked.getLockingUser()); assertTrue(isVersionIncontext(unlocked)); } @Test @Transactional public void persistNewTemplate() { WordTemplate<?> template = newTemplate(); repository.persist(template); Template<?> persisted = repository.getTemplate("test3", "de"); assertTrue(isVersionIncontext(persisted)); } @Test @Transactional public void persistTemplateWithFileStore() throws Exception { WordTemplate<?> template = newTemplate(); FileStore fileStore = mock(FileStore.class); File file = File.createTempFile("content", "docx"); OutputStream out = FileUtils.openOutputStream(file); when(fileStore.getOutStream(anyString())).thenReturn(out); repository.setFileStore(fileStore); try { repository.persist(template); File epected = FileUtils.toFile(getClass().getResource("empty.docx")); assertTrue(FileUtils.contentEquals(epected, file)); } finally { file.deleteOnExit(); } } @Test @Transactional public void persistOfLocked() throws Exception { Template<?> template1 = unlockedTemplate(); WordTemplate<?> template2 = unlockedTemplate(); template1 = repository.lockForEdit(template1, new User("user1", "user1")); byte[] content = getContent("empty.docx"); template2.getTemplateData().setContent(content, new User()); try { repository.persist(template2); fail("Exception expected"); } catch (LockingException e) { assertTrue(isVersionIncontext(template1)); } } @Test @Transactional public void changeContent() throws Exception { WordTemplate<?> template = unlockedTemplate(); byte[] content = getContent("empty.docx"); User user = new User("new_editor", "New Editor"); template.update(new ByteArrayInputStream(content), user); Template<?> peristed = repository.persist(template); assertTrue(isVersionIncontext(peristed)); } @Test @Transactional public void updateTemplateWithFileStore() throws Exception { FileStore fileStore = mock(FileStore.class); File file = File.createTempFile("content", "docx"); OutputStream out = FileUtils.openOutputStream(file); when(fileStore.getOutStream(anyString())).thenReturn(out); repository.setFileStore(fileStore); WordTemplate<?> template = unlockedTemplate(); template.getTemplateData().setContent(getContent("empty.docx"), new User()); try { repository.persist(template); File expected = FileUtils.toFile(getClass().getResource("empty.docx")); assertTrue(FileUtils.contentEquals(expected, file)); } finally { file.deleteOnExit(); } } @Test @Transactional public void deleteTemplate() { WordTemplate<?> template = unlockedTemplate(); repository.delete(template); assertFalse(isVersionIncontext(template)); } @Test @Transactional public void deleteLockedTemplate() { WordTemplate<?> template = lockedTemplate(); try { repository.delete(template); fail("Exception expected. Locked templates must not be deleted"); } catch (LockingException e) { assertTrue(isVersionIncontext(template)); } } @Test @Transactional public void delteTemplateWithFileStore() throws Exception { FileStore fileStore = mock(FileStore.class); repository.setFileStore(fileStore); WordTemplate<?> template = unlockedTemplate(); PersistentTemplate templateData = (PersistentTemplate) template.getTemplateData(); repository.delete(template); verify(fileStore, times(1)).deleteFile(anyString()); verify(fileStore, times(1)).deleteFile(templateData.getTemplateFileName()); assertFalse("template must not be in persistent context", isVersionIncontext(template)); } @Test @Transactional public void errorsWithFileStore() throws Exception { WordTemplate<?> template = unlockedTemplate(); FileStore fileStore = mock(FileStore.class); repository.setFileStore(fileStore); EntityManager entityManager = mock(EntityManager.class); when(entityManager.merge(any())).thenThrow(new PersistenceException()); repository.em = entityManager; try { repository.persist(template); fail("Exception expected"); } catch (Exception e) { verifyZeroInteractions(fileStore); } } private WordTemplate<?> newTemplate() { try { PersistentTemplate templateData = new PersistentTemplate(); templateData.setDocumentName("test3"); templateData.setLanguage("de"); templateData.setContent(getContent("empty.docx")); templateData.setCreatedAt(new Date()); templateData.setEditedAt(new Date()); templateData.setEditor(new User("user", "user")); Map<String, String> properties = new HashMap<>(); properties.put("key", "value"); templateData.setProperties(properties); MappingDetail value = new MappingDetail(); value.setModelKey("modelKey"); Map<String, MappingDetail> contentMaping = new HashedMap<String, MappingDetail>(); contentMaping.put("conentKey", value); templateData.setContentMapping(contentMaping); WordTemplate<?> template = new WordTemplate<Object>(templateData, contextFactory); return template; } catch (IOException e) { throw new RuntimeException(e); } } /** * Returns a detached locked template */ private WordTemplate<?> lockedTemplate() { PersistentTemplate template = getTemplateInContext(LOCKED_TEMPLATE); entityManager.detach(template); return new WordTemplate<Object>(template, contextFactory); } /** * Returns a detached unlocked template */ private WordTemplate<?> unlockedTemplate() { PersistentTemplate template = getTemplateInContext(UNLOCKED_TEMPLATE); entityManager.detach(template); return new WordTemplate<Object>(template, contextFactory); } private byte[] getContent(String file) throws IOException { InputStream in = null; try { in = getClass().getResourceAsStream(file); return IOUtils.toByteArray(in); } finally { IOUtils.closeQuietly(in); } } PersistentTemplate getTemplateInContext(long id) { return entityManager.find(PersistentTemplate.class, id); } private boolean isVersionIncontext(Template<?> template) { WordTemplate<?> wordTemplate = (WordTemplate<?>) template; PersistentTemplate templateData = (PersistentTemplate) wordTemplate.getTemplateData(); PersistentTemplate inContext = getTemplateInContext(templateData.getId()); if (inContext == null) { return false; } return inContext.getVersion() == templateData.getVersion(); } }