package geniusweb.profilesserver; 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 java.io.BufferedWriter; import java.io.File; import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; import java.net.URISyntaxException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.logging.Level; import org.junit.Before; import org.junit.Test; import com.fasterxml.jackson.databind.ObjectMapper; import geniusweb.profile.Profile; import geniusweb.profile.utilityspace.LinearAdditiveUtilitySpace; import geniusweb.profilesserver.events.ChangeEvent; import geniusweb.profilesserver.events.DomainChangeEvent; import geniusweb.profilesserver.events.ProfileChangeEvent; import tudelft.utilities.files.FileInfo; import tudelft.utilities.files.FileWatcher; import tudelft.utilities.immutablelist.Tuple; import tudelft.utilities.listener.Listenable; import tudelft.utilities.listener.Listener; import tudelft.utilities.logging.Reporter; /** * Most tests are using a (copy of ) a real filesystem repository. This is * because the AutoUpdatingProfilesFactory accesses the real filesystem that we * can't properly mock. * */ public class AutoUpdatingProfilesFactoryTest { private static final String JOBS = "jobs"; private static final String JOB1 = "jobs/jobs1"; private final Path REPO_DIRECTORY = Paths .get("src/main/webapp/domainsrepo/"); private List warnings; private Path copyrepodir; private AutoUpdatingProfilesRepository factory; private final long HIGHRATE = 500; // fast so that we can test quickly. private final List changes = new LinkedList<>(); @Before public void before() throws IOException, URISyntaxException { final Path dir = Files.createTempDirectory("profilestest"); copyrepodir = Paths.get(dir.toString(), "repo"); copyFolder(REPO_DIRECTORY, copyrepodir); System.out.println("copy placed in " + copyrepodir); Reporter logger = new Reporter() { @Override public void log(Level level, String string, Throwable e) { if (level.intValue() >= Level.WARNING.intValue()) { warnings.add(string); } } @Override public void log(Level level, String string) { if (level.intValue() >= Level.WARNING.intValue()) { warnings.add(string); } } }; factory = new AutoUpdatingProfilesRepository(logger) { @Override protected Path getRootDir() { return copyrepodir; } @Override protected Listenable> getFileWatcher( File file) { return new FileWatcher(file, HIGHRATE - 100, 2); } }; factory.addListener(new Listener() { @Override public void notifyChange(ChangeEvent evt) { changes.add(evt); } }); warnings = new LinkedList<>(); } /** * test loading the repo */ @Test public void loadRepoTest() throws InterruptedException { assertEquals(Collections.EMPTY_LIST, warnings); assertNotNull(factory.getDomain(JOBS)); assertNotNull(factory.getProfile(JOB1)); } @Test public void getDomainsTest() { assertTrue(factory.getDomains().size() > 2); assertTrue(factory.getDomains().contains(JOBS)); assertTrue(factory.getDomains().contains(JOBS)); assertTrue(factory.getDomains().contains("7issues")); } @Test public void removeProfileTest() throws InterruptedException { copyrepodir.resolve("jobs/jobs1.json").toFile().delete(); Thread.sleep(HIGHRATE); assertEquals(1, changes.size()); assertTrue(changes.get(0) instanceof ProfileChangeEvent); assertEquals(Collections.EMPTY_LIST, warnings); assertNotNull(factory.getDomain(JOBS)); assertNull(factory.getProfile(JOB1)); } @Test public void removeDomainTest() throws InterruptedException { copyrepodir.resolve("jobs/jobs.json").toFile().delete(); Thread.sleep(HIGHRATE); assertEquals(4, changes.size()); assertTrue(changes.get(0) instanceof ProfileChangeEvent); assertTrue(changes.get(1) instanceof ProfileChangeEvent); assertTrue(changes.get(2) instanceof ProfileChangeEvent); assertTrue(changes.get(3) instanceof DomainChangeEvent); assertEquals(1, warnings.size()); // jobs domain file missing assertNull(factory.getDomain(JOBS)); assertNull(factory.getProfile(JOB1)); } @Test public void renameDomainTest() throws InterruptedException { assertTrue(copyrepodir.resolve(JOBS).toFile() .renameTo(copyrepodir.resolve("otherjobs").toFile())); Thread.sleep(HIGHRATE); assertEquals(4, changes.size()); assertTrue(changes.get(0) instanceof ProfileChangeEvent); assertTrue(changes.get(1) instanceof ProfileChangeEvent); assertTrue(changes.get(2) instanceof ProfileChangeEvent); assertTrue(changes.get(3) instanceof DomainChangeEvent); assertEquals(1, warnings.size()); // wrong domain file, wrong profile assertNull(factory.getDomain(JOBS)); assertNull(factory.getProfile(JOB1)); assertNull(factory.getDomain("otherjobs")); } @Test public void addProfileTest() throws InterruptedException, IOException { LinearAdditiveUtilitySpace profile = (LinearAdditiveUtilitySpace) factory .getProfile(JOB1); Profile newprofile = new LinearAdditiveUtilitySpace(profile.getDomain(), "jobs9", profile.getUtilities(), profile.getWeights(), profile.getReservationBid()); ObjectMapper jackson = new ObjectMapper(); BufferedWriter writer = new BufferedWriter(new FileWriter( copyrepodir.resolve("jobs/jobs9.json").toFile())); writer.write(jackson.writeValueAsString(newprofile)); writer.close(); Thread.sleep(HIGHRATE); assertEquals(1, changes.size()); assertTrue(changes.get(0) instanceof ProfileChangeEvent); assertTrue(warnings.isEmpty()); assertNotNull(factory.getProfile("jobs/jobs2")); } /** * We add domain as jobs8 but it has internally the name jobs9. */ @Test public void addWrongProfileTest() throws InterruptedException, IOException { LinearAdditiveUtilitySpace profile = (LinearAdditiveUtilitySpace) factory .getProfile(JOB1); Profile newprofile = new LinearAdditiveUtilitySpace(profile.getDomain(), "jobs9", profile.getUtilities(), profile.getWeights(), profile.getReservationBid()); ObjectMapper jackson = new ObjectMapper(); BufferedWriter writer = new BufferedWriter(new FileWriter( copyrepodir.resolve("jobs/jobs8.json").toFile())); writer.write(jackson.writeValueAsString(newprofile)); writer.close(); Thread.sleep(HIGHRATE); // the bad profile should be completely ignored but we should get // warnings. assertEquals(0, changes.size()); assertEquals(1, warnings.size()); } @Test public void saveProfileTest() throws IOException { assertEquals(0, changes.size()); LinearAdditiveUtilitySpace profile = (LinearAdditiveUtilitySpace) factory .getProfile(JOB1); Profile newprofile = new LinearAdditiveUtilitySpace(profile.getDomain(), "jobsA", profile.getUtilities(), profile.getWeights(), profile.getReservationBid()); factory.putProfile(newprofile); // check response immediately assertEquals(1, changes.size()); assertTrue(changes.get(0) instanceof ProfileChangeEvent); // check file was written assertTrue(copyrepodir.resolve("jobs/jobsA.json").toFile().exists()); } /** * We remove jobs domain. */ @Test public void removeRootdirTest() throws InterruptedException, IOException { assertNotNull(factory.getDomain(JOBS)); delete(copyrepodir.resolve(JOBS).toFile()); Thread.sleep(HIGHRATE); assertNull(factory.getDomain(JOBS)); assertNull(factory.getProfile(JOB1)); assertEquals(4, changes.size()); assertTrue(changes.get(0) instanceof ProfileChangeEvent); assertTrue(changes.get(1) instanceof ProfileChangeEvent); assertTrue(changes.get(2) instanceof ProfileChangeEvent); assertTrue(changes.get(3) instanceof DomainChangeEvent); assertEquals(0, warnings.size()); } @Test public void testEnvVariable() throws IOException { Path dir = Files.createTempDirectory("tempdir"); // This test does not work because we can not set the env variable. // new EnvironmentVariables().set("PROFILES_ROOTDIR", "1"); System.setProperty("PROFILES_ROOTDIR", "1");// dir.toAbsolutePath().toString()); System.out.println(System.getenv("PROFILES_ROOTDIR")); } /** * Copy files and all sub-files. * * @param source * @param dest */ private void copy(Path source, Path dest) { try { Files.copy(source, dest); } catch (IOException e) { e.printStackTrace(); } } private void copyFolder(Path src, Path dest) throws IOException { Files.walk(src).forEach( source -> copy(source, dest.resolve(src.relativize(source)))); } /** * recursively delete file and all subfiles. * * @param f the file to be deleted. can be directory. * @throws IOException if file can't be deleted. This halts the delete * procedure immediately. */ private void delete(File f) throws IOException { if (f.isDirectory()) { for (File c : f.listFiles()) delete(c); } if (!f.delete()) throw new FileNotFoundException("Failed to delete file: " + f); } }