@Before public void setup() throws Exception { vd = new TestViewDef(); vd.addQuery(new DataGeneratorQuery("id", "1st", 10, 5)); vd.addQuery(new JoinQueryMapper(new DataGeneratorQuery("id", "2nd", 10, 5))); vd.addQuery(new PerRowAppendMapper(new DataGeneratorQuery("otherid", "3rd", 1, 5))); IFrameLoader loader = new StaticFrameLoader(vd); registry = new FrameRegistry(loader); registry.load(); runner = new FrameRunner(registry); }
/** * By repeating the same simple test many times with some random-ness, we can spot concurrency and * race conditions. */ @Test public void testRaceConditions() throws Exception { // should randomly take between 5-10ms to complete each one ViewDef view = new TestViewDef(); view.addQuery(new DataGeneratorQuery("id", "1st", 10, 5)); view.addQuery(new JoinQueryMapper(new DataGeneratorQuery("id", "2nd", 10, 5))); view.addQuery( new PerRowAppendMapper(new DataGeneratorQuery("otherid", "3rd", 1, 5).setDelay(5, 10))); // run the test 100 times, make sure it returns the same values each time for (int i = 0; i < 100; i++) { FrameTask task = runner.exec(view); verify(task.getAction(ViewRenderAction.class).getResults()); } }
@Test public void testMergeAppender() throws Exception { ViewDef vd = new TestViewDef(); vd.addQuery(ViewDefSamples.sq1); vd.addQuery(new JoinQueryMapper(ViewDefSamples.sq2)); RenderTask q = runner.exec(vd).getAction(ViewRenderAction.class).getResults(); assertEquals(3, q.size()); assertEquals("a1", q.getCellIdx(0, "a")); assertEquals("b1", q.getCellIdx(0, "b")); assertEquals("c1", q.getCellIdx(0, "c")); assertEquals("x1", q.getCellIdx(0, "x")); assertEquals("y1", q.getCellIdx(0, "y")); assertEquals("z1", q.getCellIdx(0, "z")); }
@Test public void testMergeAppenderFK() throws Exception { ViewDef vd = new TestViewDef(); vd.addQuery(ViewDefSamples.sq2); vd.addQuery(new JoinQueryMapper(ViewDefSamples.sq1, "id2")); FrameTask task = runner.exec(vd); System.out.println("testMergeAppenderFK\n" + task.toString()); RenderTask q = task.getAction(ViewRenderAction.class).getResults(); assertEquals(3, q.size()); assertEquals("a1", q.getCellIdx(0, "a")); assertEquals("b1", q.getCellIdx(0, "b")); assertEquals("c1", q.getCellIdx(0, "c")); assertEquals("x1", q.getCellIdx(0, "x")); assertEquals("y1", q.getCellIdx(0, "y")); assertEquals("z1", q.getCellIdx(0, "z")); }
@Test public void testPerRowAppendMapper() throws Exception { List<Map<String, Object>> data = new ArrayList<Map<String, Object>>(); data.add(Table.buildRow("foo", "bar")); // build a query that will just copy the PK field Query q2 = new AbstractQuery("idcopy", null) { @Override public void exec(RenderTask task) throws Exception { if (task instanceof RowRenderSubTask) { RowRenderSubTask subtask = (RowRenderSubTask) task; if (subtask.getRowIdx() >= 0) { task.add(Table.buildRow("idcopy", subtask.getParentRowKey())); } } } }; // regular three rows, but the second query is appended to each row ViewDef vd = new TestViewDef(); vd.addQuery(ViewDefSamples.sq1); vd.addQuery(new PerRowAppendMapper(new StaticQuery("foo", data))); vd.addQuery(new PerRowAppendMapper(q2)); // should append the queries to each other, totaling 3 rows with 7 columns apeice RenderTask q = runner.exec(vd).getAction(ViewRenderAction.class).getResults(); assertEquals(3, q.size()); assertEquals(7, q.getRowIdx(0).size()); assertEquals(7, q.getRowIdx(1).size()); assertEquals(7, q.getRowIdx(2).size()); // static data just gets added to each row assertEquals("bar", q.getCellIdx(0, "foo")); assertEquals("bar", q.getCellIdx(1, "foo")); assertEquals("bar", q.getCellIdx(2, "foo")); // q2 copies the PK assertEquals("1", q.getCellIdx(0, "idcopy")); assertEquals("2", q.getCellIdx(1, "idcopy")); assertEquals("3", q.getCellIdx(2, "idcopy")); }
@Test public void testNestedViewDefs() throws FrameInitException, FrameExecException { ViewDef def = new TestViewDef(); def.addQuery(new DataGeneratorQuery("id", "1st", 10, 5)); def.addQuery(new PerRowSubTableMapper("subview", vd)); // we expect the usual 10 rows // runner.setExecutor(null); FrameTask task = runner.exec(def); RenderTask results = task.getAction(ViewRenderAction.class).getResults(); assertEquals(10, results.size()); for (int i = 0; i < 10; i++) { // each one should have 1 column that can be verifyied as the standard results Map<String, Object> row = results.getRowIdx(i); assertTrue(row.containsKey("subview")); assertTrue(row.get("subview") instanceof RenderTask); RenderTask subview = (RenderTask) row.get("subview"); verify(subview); } }
/** * by setting specific query execution delays, we should be able to predict how long it takes to * render based on the number of threads running in parallel */ @Test public void testMultiThreadRenderingIsFaster() throws Exception { // new view def, each query should take 100ms to run ViewDef view = vd; view.addQuery(new DataGeneratorQuery("id", "1st", 10, 5).setDelay(100)); view.addQuery( new PerRowAppendMapper(new DataGeneratorQuery("otherid", "3rd", 1, 5).setDelay(100))); // w/o multi-threading, we predict it will take approximately 1.1s // query1+(query2*10) long start = System.currentTimeMillis(); runner.setExecutor(null); runner.exec(view); assertEquals(1100, (System.currentTimeMillis() - start), 220); // 20% fudge factor // with multi-threading (5 threads) we predict it will be almost 5x quicker // query1+(query2*10/5) ExecutorService exec = Executors.newFixedThreadPool(5); start = System.currentTimeMillis(); runner.setExecutor(exec); runner.exec(view); assertEquals(300, (System.currentTimeMillis() - start), 60); // 20% fudge factor }
@Test public void testErrorQuery() throws FrameInitException, FrameExecException { // errors in the primary query ViewDef vd = new TestViewDef(); vd.addQuery(new ErrorQuery("foo")); try { FrameTask task = runner.exec(vd); fail("exception expected...."); } catch (Exception ex) { // expected } // errors in other threads vd = new TestViewDef(); vd.addQuery(ViewDefSamples.sq1); vd.addQuery(new JoinQueryMapper(new ErrorQuery("foo"))); try { FrameTask task = runner.exec(vd); fail("exception expected...."); } catch (Exception ex) { // expected } }
@Test public void testQueries() throws FrameInitException { // initally there are no queries ViewDef vd = new TestViewDef(); assertEquals(0, vd.getQueries(null).size()); try { assertNull(vd.getPrimaryQuery()); fail("expected an exception when there are no queries defined"); } catch (IllegalStateException ex) { // expected } // add a query Query q = new JDSQuery("pk", ""); assertSame(q, vd.addQuery(q)); assertEquals(1, vd.getQueries(null).size()); assertSame(q, vd.getQueries(null).get(0)); assertSame(q, vd.getPrimaryQuery()); }
@Test @Ignore // timeout no longer works for the primary viewdef for now public void testTimeout() throws Exception { // should take 1s to render this ViewDef view = new TestViewDef(); view.addQuery(new DataGeneratorQuery("id", "1st", 10, 5).setDelay(1000)); // set the renderer to timeout in 500ms runner.setTimeoutMS(500); assertEquals(500, runner.getTimeoutMS()); try { runner.exec(view); fail("Expected timeout"); } catch (FrameExecException ex) { // timeout exception should be thrown (wrapped by a RenderException) assertEquals(TimeoutException.class, ex.getCause().getClass()); } }
@Test public void testUINotifyAppender() throws Exception { DummyFrameAction act = DummyFrameAction.INSTANCE; // setup JMS topic/connection/session String brokerURL = "vm://hmp-test?waitForStart=1000&broker.persistent=false&broker.deleteAllMessagesOnStartup=true"; ConnectionFactory fact = new ActiveMQConnectionFactory(brokerURL); Connection conn = fact.createConnection(); conn.start(); Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE); // setup a JMS template JmsTemplate tpl = new JmsTemplate(fact); tpl.setPubSubDomain(true); tpl.setDefaultDestinationName("ui.notify"); tpl.setReceiveTimeout(JmsTemplate.RECEIVE_TIMEOUT_NO_WAIT); Topic dest = sess.createTopic("ui.notify"); MessageConsumer consumer = sess.createConsumer(dest); assertNull(tpl.receive()); // configure the runner runner.setTimeoutMS(60000); // 1m runner.addResource(tpl); // create a viewdef with a nested UINotifier viewdef that should be done in 100ms // the rest of the time (10x100ms) should run in parallel and be done in 200ms; ((DataGeneratorQuery) vd.getPrimaryQuery()).setDelay(100); ViewDef view = new TestViewDef(); DataGeneratorQuery q1 = view.addQuery(new DataGeneratorQuery("id", "1st", 10, 5).setDelay(150)); UINotifyQueryMapper q2 = view.addQuery(new UINotifyQueryMapper("subview", vd)); // query should be done in ~150ms, rest will take another 200ms long start = System.currentTimeMillis(); FrameTask task = runner.exec(view); RenderTask q = task.getAction(ViewRenderAction.class).getResults(); assertTrue(task.getTotalTimeMS() <= 200); // generous fudge factor assertEquals(task.getTotalTimeMS(), (System.currentTimeMillis() - start), 50); // should return 10 placeholder values assertEquals(10, q.size()); assertEquals(1, q1.execCount); List<String> uuids = new ArrayList<String>(); for (int i = 0; i < q.size(); i++) { Object subview = q.getCellIdx(i, "subview"); assertTrue(subview instanceof String); uuids.add(subview.toString()); } // expecting the main task to have a single subtask (RenderTask) assertEquals(1, task.getSubTasks().size()); assertTrue(task.getSubTasks().get(0) instanceof RenderTask); assertSame(q, task.getSubTasks().get(0)); assertEquals(1, q.getSubTasks().size()); // main render task has one empty subtask for the UINotifyQueryMapper RenderTask task2 = (RenderTask) q.getSubTasks().get(0); assertSame(q2, task2.getQuery()); assertEquals(0, task2.getSubTasks().size()); // check that the JMS topic has 10 items on it, with the corresponding UUIDs for (int i = 0; i < 10; i++) { Message msg = consumer.receive(500); assertNotNull(msg); String uuid = msg.getStringProperty("uid"); uuids.remove(uuid); } assertNull(consumer.receiveNoWait()); // nothing left // vd should have been executed 10x and found all UUIDs DataGeneratorQuery q3 = (DataGeneratorQuery) vd.getPrimaryQuery(); assertEquals(10, q3.execCount); assertEquals(0, uuids.size()); }