@Test
public void customerRetentionScenarioDsl() {

    Trigger trigger = new Trigger(TEST_TENANT, "customer-retention-scenario", "Customer Retention Scenario");
    String expression = "event:groupBy(tags.traceId):" +
            "filter((category == \"Credit Check\" && text == \"Exceptionally Good\") || " +
                   "(category == \"Stock Check\" && text == \"Out of Stock\")):" +
            "having(count > 1, count.tags.accountId == 1)";
    ExternalCondition condition = new ExternalCondition(trigger.getId(), FIRING, DATA_ID, ALERTER_ID, expression);
    Expression exp = new Expression(Arrays.asList(new FullTrigger(trigger, null, Arrays.asList(condition))));
    String drl = exp.getDrl();
    // System.out.println(drl);
    startSession(drl);
    // Init t0
    clock.setStartupTime(1);
    long now = clock.getCurrentTime();
    Event e1 = new Event(TEST_TENANT, uuid(), now, DATA_ID, "Credit Check", "Exceptionally Good");
    e1.addTag("duration", "1000");
    e1.addTag("traceId", "trace1");
    e1.addTag("accountId", "user1");
    Event e11 = new Event(TEST_TENANT, uuid(), now, DATA_ID, "Credit Check", "Exceptionally Good");
    e11.addTag("duration", "1000");
    e11.addTag("traceId", "trace4");
    e11.addTag("accountId", "user2");
    insert(e1, e11);
    // t0 + 1000
    now = clock.advanceTime(1000, TimeUnit.MILLISECONDS);
    Event e2 = new Event(TEST_TENANT, uuid(), now, DATA_ID, "Stock Check", "Out of Stock");
    e2.addTag("duration", "2000");
    e2.addTag("traceId", "trace1");
    e2.addTag("accountId", "user1");
    Event e12 = new Event(TEST_TENANT, uuid(), now, DATA_ID, "Stock Check", "Out of Stock");
    e12.addTag("duration", "2000");
    e12.addTag("traceId", "trace4");
    e12.addTag("accountId", "user2");
    insert(e2, e12);
    // t0 + 2000
    now = clock.advanceTime(1000, TimeUnit.MILLISECONDS);
    Event e3 = new Event(TEST_TENANT, uuid(), now, DATA_ID, "Credit Check", "Good");
    e3.addTag("duration", "1500");
    e3.addTag("traceId", "trace2");
    e3.addTag("accountId", "user1");
    Event e13 = new Event(TEST_TENANT, uuid(), now, DATA_ID, "Credit Check", "Good");
    e13.addTag("duration", "1500");
    e13.addTag("traceId", "trace5");
    e13.addTag("accountId", "user2");
    insert(e3, e13);
    // t0 + 3000
    now = clock.advanceTime(1000, TimeUnit.MILLISECONDS);
    Event e4 = new Event(TEST_TENANT, uuid(), now, DATA_ID, "Stock Check", "Out of Stock");
    e4.addTag("duration", "2000");
    e4.addTag("traceId", "trace2");
    e4.addTag("accountId", "user1");
    Event e14 = new Event(TEST_TENANT, uuid(), now + 3, DATA_ID, "Stock Check", "Out of Stock");
    e14.addTag("duration", "2000");
    e14.addTag("traceId", "trace5");
    e14.addTag("accountId", "user2");
    insert(e4, e14);
    // t0 + 4000
    now = clock.advanceTime(1000, TimeUnit.MILLISECONDS);
    Event e5 = new Event(TEST_TENANT, uuid(), now, DATA_ID, "Credit Check", "Exceptionally Good");
    e5.addTag("duration", "1500");
    e5.addTag("traceId", "trace3");
    e5.addTag("accountId", "user1");
    Event e15 = new Event(TEST_TENANT, uuid(), now, DATA_ID, "Credit Check", "Exceptionally Good");
    e15.addTag("duration", "1500");
    e15.addTag("traceId", "trace6");
    e15.addTag("accountId", "user2");
    insert(e5, e15);
    // t0 + 5000
    now = clock.advanceTime(1000, TimeUnit.MILLISECONDS);
    Event e6 = new Event(TEST_TENANT, uuid(), now, DATA_ID, "Stock Check", "Available");
    e6.addTag("duration", "2000");
    e6.addTag("traceId", "trace3");
    e6.addTag("accountId", "user1");
    Event e16 = new Event(TEST_TENANT, uuid(), now, DATA_ID, "Stock Check", "Available");
    e16.addTag("duration", "2000");
    e16.addTag("traceId", "trace6");
    e16.addTag("accountId", "user2");
    insert(e6, e16);
    stopSession();
    Assert.assertEquals(2, results.size());
    results.stream().forEach(e -> {
        String traceId = e.getContext().get("traceId");
        Assert.assertTrue(traceId.equals("trace1") || traceId.equals("trace4"));
        /*
            System.out.println("Event: ");
            System.out.println(e);
            System.out.println("Source events:");
            extractEvents(e).stream().forEach(extracted -> {
                System.out.println(extracted);
            });
            System.out.println("\n");
        */
    });
}