package com.temenos.interaction.loader.properties; /* * #%L * interaction-dynamic-loader * %% * Copyright (C) 2012 - 2016 Temenos Holdings N.V. * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% */ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.nio.file.attribute.FileTime; import java.util.ArrayList; import java.util.List; import java.util.Properties; import org.junit.Test; import org.mockito.Mockito; import org.springframework.context.ApplicationContext; import org.springframework.core.io.Resource; import com.temenos.interaction.core.loader.FileEvent; import com.temenos.interaction.loader.properties.ReloadablePropertiesFactoryBean.ChangeIndexFileProvider; import com.temenos.interaction.loader.xml.resource.notification.XmlModificationNotifier; public class ReloadablePropertiesFactoryBeanTest { @Test public void testSetListeners() throws Exception { List<ReloadablePropertiesListener<Resource>> listeners = new ArrayList<>(); ReloadablePropertiesListener<Resource> listener1 = mock(ReloadablePropertiesListener.class); ReloadablePropertiesListener<Resource> listener2 = mock(ReloadablePropertiesListener.class); listeners.add(listener1); listeners.add(listener2); ReloadablePropertiesFactoryBean rp = new ReloadablePropertiesFactoryBean(); rp.setListeners(listeners); assertEquals(2, rp.getListeners().size()); assertTrue(rp.getListeners().contains(listener1)); assertTrue(rp.getListeners().contains(listener2)); } @Test public void testGetListeners() throws Exception { List<ReloadablePropertiesListener<Resource>> listeners = new ArrayList<>(); ReloadablePropertiesListener<Resource> listener1 = mock(ReloadablePropertiesListener.class); ReloadablePropertiesListener<Resource> listener2 = mock(ReloadablePropertiesListener.class); listeners.add(listener1); listeners.add(listener2); ReloadablePropertiesFactoryBean rp = new ReloadablePropertiesFactoryBean(); assertTrue(rp.getListeners().isEmpty()); rp.setListeners(listeners); assertEquals(2, rp.getListeners().size()); assertTrue(rp.getListeners().contains(listener1)); assertTrue(rp.getListeners().contains(listener2)); } @Test public void testSetProperties() throws Exception { Properties properties = new Properties(); properties.put(1, "one"); properties.put(2, "two"); ReloadablePropertiesFactoryBean rp = new ReloadablePropertiesFactoryBean(); rp.setProperties(properties); assertEquals(2, rp.getProperties().size()); assertTrue(rp.getProperties().contains("one")); assertTrue(rp.getProperties().containsKey(1)); assertEquals("one", rp.getProperties().get(1)); assertTrue(rp.getProperties().contains("two")); assertTrue(rp.getProperties().containsKey(2)); assertEquals("two", rp.getProperties().get(2)); } @Test public void testCreateInstance() throws Exception { ReloadablePropertiesFactoryBean rp = new ReloadablePropertiesFactoryBean(); assertTrue(rp.isSingleton()); ApplicationContext ctx = mock(ApplicationContext.class); Resource[] resources = new Resource[0]; when(ctx.getResources(any(String.class))).thenReturn(resources); rp.setApplicationContext(ctx); Properties properties = new Properties(); properties.put(1, "one"); properties.put(2, "two"); rp.setProperties(properties); List<ReloadablePropertiesListener<Resource>> listeners = new ArrayList<>(); ReloadablePropertiesListener<Resource> listener1 = mock(ReloadablePropertiesListener.class); ReloadablePropertiesListener<Resource> listener2 = mock(ReloadablePropertiesListener.class); listeners.add(listener1); listeners.add(listener2); rp.setListeners(listeners); String[] patterns = { "*" }; when(listener1.getResourcePatterns()).thenReturn(patterns); when(listener2.getResourcePatterns()).thenReturn(patterns); XmlModificationNotifier xmlNotifier = mock(XmlModificationNotifier.class); rp.setXmlNotifier(xmlNotifier); ReloadablePropertiesBase newInstance = (ReloadablePropertiesBase) rp.createInstance(); assertEquals(rp.getProperties(), newInstance.getProperties()); assertEquals(rp.getListeners(), newInstance.getListeners()); } @Test(expected=RuntimeException.class) public void testCreateInstanceNotSingleton() throws Exception { ReloadablePropertiesFactoryBean rp = new ReloadablePropertiesFactoryBean(); rp.setSingleton(false); rp.createInstance(); } @Test public void testReload() throws Exception { ReloadablePropertiesFactoryBean rp = new ReloadablePropertiesFactoryBean(); String rootPath = "models-gen/src/generated/iris"; Path root = Paths.get(rootPath); Files.createDirectories(root); Path tmp1 = Paths.get(rootPath + "/metadata-customer.xml"); if(!Files.exists(tmp1)) Files.createFile(tmp1); Path tmp2 = Paths.get(rootPath + "/IRIS-customer.properties"); if(!Files.exists(tmp2)) Files.createFile(tmp2); Resource[] resources = new Resource[2]; Resource resource1 = mock(Resource.class); when(resource1.getURI()).thenReturn(tmp1.toUri()); when(resource1.getURL()).thenReturn(tmp1.toUri().toURL()); Resource resource2 = mock(Resource.class); when(resource2.getURI()).thenReturn(tmp2.toUri()); when(resource2.getURL()).thenReturn(tmp2.toUri().toURL()); resources[0] = resource1; resources[1] = resource2; ApplicationContext ctx = mock(ApplicationContext.class); when(ctx.getResources(any(String.class))).thenReturn(resources); rp.setApplicationContext(ctx); // set last modified time of the lastChange file to the maximum long // so that the class believes that new changes should be processed Path lastChange = Paths.get("models-gen/lastChange"); if(Files.exists(lastChange)) Files.delete(lastChange); Files.createFile(lastChange); // add the files file to the lastChange file index byte[] tmp1FileNameBytes = (tmp1.toString() + System.getProperty("line.separator")).getBytes(); Files.write(lastChange, tmp1FileNameBytes, StandardOpenOption.APPEND); byte[] tmp2FileNameBytes = tmp2.toString().getBytes(); Files.write(lastChange, tmp2FileNameBytes, StandardOpenOption.APPEND); // set the modified time for one year ahead Files.setAttribute(lastChange, "lastModifiedTime", FileTime.fromMillis(System.currentTimeMillis() + 31536000000L)); XmlModificationNotifier xmlNotifier = new XmlModificationNotifier(); XmlModificationNotifier spy = Mockito.spy(xmlNotifier); Mockito.doNothing().when(spy).execute(any(FileEvent.class)); rp.setXmlNotifier(spy); // this is the way to create an instance of the private variable reloadableProperties... rp.createInstance(); rp.reload(false); verify(spy).execute(any(FileEvent.class)); // TODO: we should verify that the properties are reloaded, but currently // there's no way to do this... } @Test public void testReloadForced() throws Exception { ReloadablePropertiesFactoryBean rp = new ReloadablePropertiesFactoryBean(); String rootPath = "models-gen/src/generated/iris"; Path root = Paths.get(rootPath); Files.createDirectories(root); Path tmp1 = Paths.get(rootPath + "/metadata-customer.xml"); if(!Files.exists(tmp1)) Files.createFile(tmp1); Path tmp2 = Paths.get(rootPath + "/IRIS-customer.properties"); if(!Files.exists(tmp2)) Files.createFile(tmp2); Resource[] resources = new Resource[2]; Resource resource1 = mock(Resource.class); when(resource1.getURI()).thenReturn(tmp1.toUri()); when(resource1.getURL()).thenReturn(tmp1.toUri().toURL()); Resource resource2 = mock(Resource.class); when(resource2.getURI()).thenReturn(tmp2.toUri()); when(resource2.getURL()).thenReturn(tmp2.toUri().toURL()); resources[0] = resource1; resources[1] = resource2; ApplicationContext ctx = mock(ApplicationContext.class); when(ctx.getResources(any(String.class))).thenReturn(resources); rp.setApplicationContext(ctx); // set last modified time of the lastChange file to 0 // so that the class only reloads if it is forced to Path lastChange = Paths.get("models-gen/lastChange"); if(Files.exists(lastChange)) Files.delete(lastChange); Files.createFile(lastChange); // add the files file to the lastChange file index byte[] tmp1FileNameBytes = (tmp1.toString() + System.getProperty("line.separator")).getBytes(); Files.write(lastChange, tmp1FileNameBytes, StandardOpenOption.APPEND); byte[] tmp2FileNameBytes = tmp2.toString().getBytes(); Files.write(lastChange, tmp2FileNameBytes, StandardOpenOption.APPEND); // set the modified time to 0 Files.setAttribute(lastChange, "lastModifiedTime", FileTime.fromMillis(0)); XmlModificationNotifier xmlNotifier = new XmlModificationNotifier(); XmlModificationNotifier spy = Mockito.spy(xmlNotifier); Mockito.doNothing().when(spy).execute(any(FileEvent.class)); rp.setXmlNotifier(spy); // here we force the reload rp.createInstance(); verify(spy).execute(any(FileEvent.class)); // TODO: we should verify that the properties are reloaded, but currently // there's no way to do this... } @Test public void testReloadCacheFileUtil(){ ReloadablePropertiesFactoryBean rp = new ReloadablePropertiesFactoryBean(); //check location returned for application (app-test1-iris) ChangeIndexFileProvider changeLocationPresent = rp.new ChangeIndexFileProvider( "app-test1-iris=/app/test1/iris/lastChange,app-test2-iris=/app/test2/iris/lastChange","app-test1-iris"); assertNotNull(changeLocationPresent.getChangeIndexFile()); assertTrue(changeLocationPresent.getChangeIndexFile().toString().endsWith(Paths.get("/app/test1/iris/lastChange").toString())); //check null returned as location for the application not provided in configuration (app-test3-iris) ChangeIndexFileProvider changeLocationAbsent = rp.new ChangeIndexFileProvider( "app-test1-iris=/app/test1/iris/lastChange,app-test2-iris=/app/test2/iris/lastChange","app-test3-iris"); assertNull(changeLocationAbsent.getChangeIndexFile()); //check default location is provided if the config is missing ChangeIndexFileProvider changeLocationDefault = rp.new ChangeIndexFileProvider( "\\workspace\\test-app\\lastChange,app-test2-iris=/app/test2/iris/lastChange","app-test3-iris"); assertNotNull(changeLocationDefault.getChangeIndexFile()); assertTrue(changeLocationDefault.getChangeIndexFile().toString().endsWith(Paths.get("workspace\\test-app\\lastChange").toString())); //OLD: check default location alone is provided ChangeIndexFileProvider changeLocationOnlyDefault = rp.new ChangeIndexFileProvider( "\\workspace\\test-app\\lastChange","app-test3-iris"); assertNotNull(changeLocationOnlyDefault.getChangeIndexFile()); assertTrue(changeLocationOnlyDefault.getChangeIndexFile().toString().endsWith(Paths.get("workspace\\test-app\\lastChange").toString())); //check default returned if the config is having invalid value ChangeIndexFileProvider changeLocationInvalid = rp.new ChangeIndexFileProvider( "\\workspace\\test-app\\lastChange,app-test2-iris= ","app-test2-iris"); assertNotNull(changeLocationInvalid.getChangeIndexFile()); assertTrue(changeLocationInvalid.getChangeIndexFile().toString().endsWith(Paths.get("workspace\\test-app\\lastChange").toString())); } }