package ch.elexis.core.ui.tests; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.util.ArrayList; import java.util.Calendar; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import org.junit.BeforeClass; import org.junit.Test; import ch.elexis.core.ui.actions.BackgroundJob; import ch.elexis.core.ui.actions.BackgroundJob.BackgroundJobListener; import ch.elexis.core.ui.actions.HistoryLoader; import ch.elexis.core.ui.actions.KonsFilter; import ch.elexis.data.Fall; import ch.elexis.data.Konsultation; import ch.elexis.data.Patient; import ch.rgw.tools.TimeTool; public class HistoryLoaderTests implements BackgroundJobListener { private static Patient patGriss, patSter, patKum, patPaal; @BeforeClass public static void setUpBeforeClass() throws Exception{ //test patients patGriss = new Patient("Grissemann", "Christoph", "17.05.66", Patient.MALE); patSter = new Patient("Stermann", "Dirk", "07.12.65", Patient.MALE); patKum = new Patient("Kummer", "Christa", "08.09.64", Patient.FEMALE); patPaal = new Patient("Paal", "Günther", "23.03.62", Patient.MALE); } private int finishedLoaders; private ArrayList<Konsultation> historyDisplaylKons; private HistoryLoader historyDisplayLoader; @Test public void testExecuteWith3Consultations() throws InterruptedException{ // init some specific sample data ArrayList<Konsultation> lCons = new ArrayList<Konsultation>(); //case and consultation 1 Fall c1 = patPaal.neuerFall("TstCase1-Paal", "TestAccident", "UVG"); c1.setBeginnDatum("19.11.2015"); Konsultation cons1 = new Konsultation(c1); cons1.setDatum("20.11.2015", true); lCons.add(cons1); //case and consultation 2 Fall c2 = patPaal.neuerFall("TstCase2-Paal", "TestIllness", "KVG"); c2.setBeginnDatum("01.01.2014"); Konsultation cons2 = new Konsultation(c2); cons2.setDatum("24.01.2014", true); lCons.add(cons2); //case and consultation 3 Fall c3 = patPaal.neuerFall("TstCase3-Paal", "TestPrevention", "MV"); c3.setBeginnDatum("13.11.2015"); Konsultation cons3 = new Konsultation(c3); cons3.setDatum("13.11.2015", true); lCons.add(cons3); // pass values to history loader and schedule HistoryLoader loader = new HistoryLoader(new StringBuilder(), lCons); loader.schedule(0); loader.join(); // wait for finish assertEquals(3, loader.getSize()); String dataString = (String) loader.getData(); String[] split = dataString.split("<p>"); // 3 cases/cons + starting tag assertEquals(4, split.length); // consultation date assertTrue(split[1].contains("20.11.2015")); // check case details displayed assertTrue(split[1].contains("UVG: TestAccident - TstCase1-Paal(19.11.2015- offen)")); // TestCase3 happened before TestCase2 and therefore will be at 2 position // check consultation date and case details assertTrue(split[2].contains("13.11.2015")); assertTrue(split[2].contains("MV: TestPrevention - TstCase3-Paal(13.11.2015- offen)")); // TestCase2 is the oldest and therefore at last place // check consultation date and case details assertTrue(split[3].contains("01.01.2014")); assertTrue(split[3].contains("KVG: TestIllness - TstCase2-Paal(01.01.2014- offen)")); //cancel job loader.cancel(); } @Test public void testExecuteWithRandomConsultations() throws InterruptedException{ int consListSize = 13; ArrayList<Konsultation> consList = generateTestConsultationAndCases(patPaal, consListSize); HistoryLoader loader = new HistoryLoader(new StringBuilder(), consList); loader.schedule(0); loader.join(); // wait for job to finish // check size assertEquals(consListSize, loader.getSize()); String dataString = (String) loader.getData(); String[] split = dataString.split("<p>"); // cases/cons + starting tag assertEquals(consListSize + 1, split.length); // check consultation date an case details for (int i = 0; i < consList.size(); i++) { String caseConsInfo = split[i + 1]; String consId = getInfoConsId(caseConsInfo); assertNotNull(consId); Konsultation cons = getConsFromList(consId, consList); assertNotNull(cons); String consDate = cons.getDatum(); String caseBeginDate = cons.getFall().getBeginnDatum(); assertTrue(caseConsInfo.contains(consDate)); assertTrue(caseConsInfo.contains("(" + caseBeginDate + "- offen)")); } //cancel job loader.cancel(); } @Test public void testExecuteFromDifferentThreads() throws InterruptedException, ExecutionException{ // init some test data int nrConsSter = 50; int nrConsGriss = 40; int nrOfConsKum = 30; removeTestConsultationAndCases(patSter); removeTestConsultationAndCases(patKum); removeTestConsultationAndCases(patGriss); List<Konsultation> consSter = generateTestConsultationAndCases(patSter, nrConsSter); List<Konsultation> consKum = generateTestConsultationAndCases(patKum, nrOfConsKum); List<Konsultation> consGriss = generateTestConsultationAndCases(patGriss, nrConsGriss); ExecutorService executorService = Executors.newCachedThreadPool(); List<LoaderCallable> callables = new ArrayList<LoaderCallable>(); for (int i = 0; i < 10; i++) { callables.add(new LoaderCallable(patGriss, new StringBuilder())); callables.add(new LoaderCallable(patSter, new StringBuilder())); callables.add(new LoaderCallable(patKum, new StringBuilder())); } int loadersSize = callables.size(); finishedLoaders = 0; // invoke all tasks and check data List<Future<LoaderData>> futures = executorService.invokeAll(callables); // wait for all loaders to finish // if test is blocking here, make sure test is NOT running in UI thread while (finishedLoaders < loadersSize) { Thread.sleep(100); } for (Future<LoaderData> future : futures) { LoaderData loaderData = future.get(); List<Konsultation> consList = null; if (loaderData.patient == patGriss) { consList = consGriss; } else if (loaderData.patient == patSter) { consList = consSter; } else if (loaderData.patient == patKum) { consList = consKum; } String result = (String) loaderData.loader.getData(); testLoaderResult(result, consList); } executorService.shutdown(); } private class ThreadSaveTimeToolRunnable implements Runnable { private boolean failed = false; private String failedToString; @Override public void run(){ TimeTool tool = new TimeTool("01.01.2020"); while (!failed) { try { Thread.sleep(1); } catch (InterruptedException e) { // ignore } String toString = tool.toString(TimeTool.DATE_GER); if (!toString.equals("01.01.2020")) { failed = true; failedToString = toString; } } } public boolean isFailed(){ return failed; } public String getFailedToString(){ return failedToString; } } @Test public void testExecuteThreadSafeTimeTool() throws InterruptedException{ historyDisplaylKons = new ArrayList<Konsultation>(20); // init some test data int nrConsGriss = 40; removeTestConsultationAndCases(patGriss); List<Konsultation> consGriss = generateTestConsultationAndCases(patGriss, nrConsGriss); // start Thread using TimeTool ExecutorService executorService = Executors.newSingleThreadExecutor(); ThreadSaveTimeToolRunnable toolRunnable = new ThreadSaveTimeToolRunnable(); executorService.execute(toolRunnable); for (int i = 0; i < 100; i++) { historyDisplayStop(); historyDisplayLoad(patGriss); historyDisplayStart(); // wait for all loaders to finish // if test is blocking here, make sure test is NOT running in UI thread while (historyDisplayLoader.getData() == null) { Thread.sleep(10); } String result = (String) historyDisplayLoader.getData(); assertNotNull(result); testLoaderResult(result, consGriss); if (toolRunnable.isFailed()) { fail("TimeTool not 01.01.2020 but [" + toolRunnable.getFailedToString() + "]"); } } executorService.shutdown(); } @Test public void testExecuteLikeHistoryDisplay() throws InterruptedException{ historyDisplaylKons = new ArrayList<Konsultation>(20); // init some test data int nrConsSter = 50; int nrConsGriss = 40; int nrOfConsKum = 30; removeTestConsultationAndCases(patSter); removeTestConsultationAndCases(patKum); removeTestConsultationAndCases(patGriss); List<Konsultation> consSter = generateTestConsultationAndCases(patSter, nrConsSter); List<Konsultation> consKum = generateTestConsultationAndCases(patKum, nrOfConsKum); List<Konsultation> consGriss = generateTestConsultationAndCases(patGriss, nrConsGriss); for (int i = 0; i < 100; i++) { finishedLoaders = 0; historyDisplayStop(); historyDisplayLoad(patSter); historyDisplayStart(); Thread.sleep(10); historyDisplayStop(); historyDisplayLoad(patKum); historyDisplayStart(); Thread.sleep(10); historyDisplayStop(); historyDisplayLoad(patGriss); historyDisplayStart(); // wait for all loaders to finish // if test is blocking here, make sure test is NOT running in UI thread while (historyDisplayLoader.getData() == null) { Thread.sleep(500); } String result = (String) historyDisplayLoader.getData(); assertNotNull(result); testLoaderResult(result, consGriss); } } public void historyDisplayStart(){ historyDisplayStart(null); } public void historyDisplayStart(KonsFilter f){ historyDisplayStop(); historyDisplayLoader = new HistoryLoader(new StringBuilder(), historyDisplaylKons, false); historyDisplayLoader.setFilter(f); historyDisplayLoader.addListener(this); historyDisplayLoader.schedule(); } public void historyDisplayStop(){ if (historyDisplayLoader != null) { historyDisplayLoader.removeListener(this); historyDisplayLoader.cancel(); } } public void historyDisplayLoad(Fall fall, boolean clear){ if (clear) { historyDisplaylKons.clear(); } if (fall != null) { Konsultation[] kons = fall.getBehandlungen(true); for (Konsultation k : kons) { historyDisplaylKons.add(k); } } } public void historyDisplayLoad(Patient pat){ if (pat != null) { historyDisplaylKons.clear(); Fall[] faelle = pat.getFaelle(); for (Fall f : faelle) { historyDisplayLoad(f, false); } } } private Konsultation getConsFromList(String consId, List<Konsultation> consList){ for (Konsultation konsultation : consList) { if (konsultation.getId().equals(consId)) { return konsultation; } } return null; } private String getInfoConsId(String caseConsInfo){ int endIdx = caseConsInfo.indexOf("\">"); int startIdx = caseConsInfo.indexOf("=\""); if (endIdx != -1 && startIdx != -1) { return caseConsInfo.substring(startIdx + 2, endIdx); } return null; } private void testLoaderResult(String result, List<Konsultation> consList){ String[] split = result.split("<p>"); // check consultation date an case details for (int i = 0; i < split.length - 1; i++) { String caseConsInfo = split[i + 1]; String consId = getInfoConsId(caseConsInfo); assertNotNull(consId); Konsultation cons = getConsFromList(consId, consList); assertNotNull(cons); String consDate = cons.getDatum(); System.out.println("Cons date [" + consDate + "]"); String caseBeginDate = cons.getFall().getBeginnDatum(); System.out.println("Case date [" + consDate + "]"); if (!caseConsInfo.contains(consDate)) { System.out.println("No cons date [" + consDate + "] in [" + caseConsInfo + "]"); } assertTrue(caseConsInfo.contains(consDate)); assertTrue(caseConsInfo.contains("(" + caseBeginDate + "- offen)")); } } /** * reconstruct ui event when patien is selected * * @param pat * @param expectedSize * @throws InterruptedException */ private HistoryLoader scheduleLoaderFor(Patient pat, StringBuilder sb) throws InterruptedException{ // clear list and populate with patients consultations ArrayList<Konsultation> lCons = new ArrayList<Konsultation>(); Fall[] cases = pat.getFaelle(); for (Fall c : cases) { Konsultation[] consList = c.getBehandlungen(true); for (Konsultation cons : consList) { lCons.add(cons); } } HistoryLoader loader = new HistoryLoader(sb, lCons, false); loader.addListener(this); loader.schedule(); return loader; } private class LoaderData { private Patient patient; private HistoryLoader loader; } private class LoaderCallable implements Callable<LoaderData> { private Patient patient; private StringBuilder sb; public LoaderCallable(Patient patient, StringBuilder sb){ this.patient = patient; this.sb = sb; } @Override public LoaderData call() throws Exception{ LoaderData ret = new LoaderData(); ret.loader = scheduleLoaderFor(patient, sb); ret.patient = patient; return ret; } } /** * generate test cases and consultation with random dates between 1999 and 2015 * * @param pat * Patient to which cases and cons shall be added * @param nrOfCons * how many cases/cons you'd like to add * @return list a sorted list (newest-> oldest) of consultations with belonging cases from this * patient */ private static ArrayList<Konsultation> generateTestConsultationAndCases(Patient pat, int nrOfCons){ ArrayList<Konsultation> consList = new ArrayList<Konsultation>(); for (int seqNr = 1; seqNr <= nrOfCons; seqNr++) { // generate a random test date Calendar cal = Calendar.getInstance(); int year = randBetween(1999, 2015); cal.set(Calendar.YEAR, year); int dayOfYear = randBetween(1, cal.getActualMaximum(Calendar.DAY_OF_YEAR)); cal.set(Calendar.DAY_OF_YEAR, dayOfYear); // create test case and consultation Fall testCase = pat.neuerFall("TstCase" + seqNr, pat.getLabel(true) + "_tests", "KVG"); testCase.setBeginnDatum(formatCalendarToString(cal)); // set cons date to next for every second testcase if (seqNr % 2 == 0) { cal.set(Calendar.DAY_OF_YEAR, cal.get(Calendar.DAY_OF_YEAR) + 1); } Konsultation testCons = new Konsultation(testCase); testCons.setDatum(formatCalendarToString(cal), true); consList.add(testCons); } return consList; } private static void removeTestConsultationAndCases(Patient pat){ Fall[] faelle = pat.getFaelle(); for (Fall fall : faelle) { Konsultation[] konsultationen = fall.getBehandlungen(true); for (Konsultation konsultation : konsultationen) { konsultation.delete(); } fall.delete(); } } /** * formats the date * * @param cal * @return date of this format dd.MM.yyyy */ private static String formatCalendarToString(Calendar cal){ return cal.get(Calendar.DAY_OF_MONTH) + "." + cal.get(Calendar.MONTH) + "." + cal.get(Calendar.YEAR); } private static int randBetween(int start, int end){ return start + (int) Math.round(Math.random() * (end - start)); } @Override public void jobFinished(BackgroundJob j){ if (j instanceof HistoryLoader) { HistoryLoader loader = (HistoryLoader) j; finishedLoaders++; } } }