From 1276e20399a90d68351cc6353fa5ded2ac4820f2 Mon Sep 17 00:00:00 2001 From: Zellweger Christof Ralf Date: Tue, 23 Jun 2015 11:49:08 +0200 Subject: [PATCH 1/2] ATEST-81: - fixing serialisation - adding tests --- .../ch/psi/daq/rest/DaqRestController.java | 2 +- .../psi/daq/rest/queries/AbstractQuery.java | 91 +++++++--- .../daq/rest/queries/BinningStrategyEnum.java | 13 ++ .../psi/daq/rest/queries/PulseRangeQuery.java | 36 +--- .../psi/daq/rest/queries/TimeRangeQuery.java | 88 ++-------- .../daq/test/rest/AbstractDaqRestTest.java | 3 +- .../rest/DaqRestApplicationConfiguration.java | 3 +- .../rest/controller/DaqControllerTest.java | 51 ++++-- .../test/rest/queries/AbstractQueryTest.java | 15 ++ .../rest/queries/AbstractQueryTestTest.java | 164 ++++++++++++++++++ .../test/rest/queries/TimeRangeQueryTest.java | 73 ++++++++ src/test/resources/test-requests.txt | 18 +- 12 files changed, 413 insertions(+), 144 deletions(-) create mode 100644 src/main/java/ch/psi/daq/rest/queries/BinningStrategyEnum.java create mode 100644 src/test/java/ch/psi/daq/test/rest/queries/AbstractQueryTest.java create mode 100644 src/test/java/ch/psi/daq/test/rest/queries/AbstractQueryTestTest.java create mode 100644 src/test/java/ch/psi/daq/test/rest/queries/TimeRangeQueryTest.java diff --git a/src/main/java/ch/psi/daq/rest/DaqRestController.java b/src/main/java/ch/psi/daq/rest/DaqRestController.java index 9747f1d..b5e18c0 100644 --- a/src/main/java/ch/psi/daq/rest/DaqRestController.java +++ b/src/main/java/ch/psi/daq/rest/DaqRestController.java @@ -53,7 +53,7 @@ public class DaqRestController { * @throws IOException */ @RequestMapping(value = "/timerange") - public void pulseRange(@RequestBody TimeRangeQuery query, HttpServletResponse res) throws IOException { + public void timeRange(@RequestBody TimeRangeQuery query, HttpServletResponse res) throws IOException { logger.debug("TimeRangeQuery received: {}", query); diff --git a/src/main/java/ch/psi/daq/rest/queries/AbstractQuery.java b/src/main/java/ch/psi/daq/rest/queries/AbstractQuery.java index 1714195..9352b94 100644 --- a/src/main/java/ch/psi/daq/rest/queries/AbstractQuery.java +++ b/src/main/java/ch/psi/daq/rest/queries/AbstractQuery.java @@ -5,13 +5,17 @@ import java.util.LinkedHashSet; import java.util.List; import org.apache.commons.lang3.builder.ReflectionToStringBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.util.Assert; import ch.psi.daq.cassandra.reader.Ordering; import ch.psi.daq.hazelcast.query.Aggregation; import ch.psi.daq.hazelcast.query.AggregationType; import ch.psi.daq.hazelcast.query.Query; -import ch.psi.daq.hazelcast.query.bin.BinIntervalCalculator; +import ch.psi.daq.hazelcast.query.bin.BinningStrategy; +import ch.psi.daq.hazelcast.query.bin.BinningStrategyFactory; +import ch.psi.daq.hazelcast.query.range.QueryRange; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; @@ -34,7 +38,9 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo; @Type(value = TimeRangeQuery.class, name = "timerange"), }) public abstract class AbstractQuery implements Query { - + + private static Logger logger = LoggerFactory.getLogger(AbstractQuery.class); + private List channels; private LinkedHashSet fields; @@ -47,39 +53,67 @@ public abstract class AbstractQuery implements Query { private Ordering ordering; + private BinningStrategy binningStrategy; + + private BinningStrategyEnum binningStrategyEnum; + + private QueryRange queryRange; + /** * - * @param isOrderDescending whether to add a 'orderBy' clause into the database query - * @param channelIds all the channelIds (channel names) we want to query + * @param ordering whether to add a 'orderBy' clause into the database query + * @param channels all the channelIds (channel names) we want to query * @param fields the fields (who map to fields in the DB) we are interested in returning to the * client, needs to be in insertion order (hence the {@link LinkedHashSet} type) + * @param queryRange TODO */ @JsonCreator public AbstractQuery( // note that those annotations are needed for the polymorphic // mapping to work correctly @JsonProperty(value = "ordering") Ordering ordering, - @JsonProperty(value = "channels") List channelIds, + @JsonProperty(value = "channels") List channels, @JsonProperty(value = "fields") LinkedHashSet fields, + @JsonProperty(value = "binningStrategy") BinningStrategyEnum binningStrategyEnum, + @JsonProperty(value = "binDuration") long binDurationOrBinCount, @JsonProperty(value = "aggregateChannels") boolean aggregateChannels, @JsonProperty(value = "aggregationType") AggregationType aggregationType, - @JsonProperty(value = "aggregations") List aggregations) { + @JsonProperty(value = "aggregations") List aggregations, + @JsonProperty(value = "queryRange") QueryRange queryRange) { this.ordering = ordering; this.aggregateChannels = aggregateChannels; this.aggregationType = aggregationType; + this.aggregations = aggregations; + this.queryRange = queryRange; - if (channelIds == null || fields == null) { - throw new IllegalArgumentException("sourceIds and/or fields cannot be null."); - } - Assert.notNull(channelIds, "channel name must not be null."); + Assert.notNull(channels, "channel name must not be null."); Assert.notNull(fields, "field, i.e. property, names must not be null."); - this.channels = channelIds; + this.channels = channels; this.fields = fields; - this.aggregations = aggregations; + + this.binningStrategyEnum = binningStrategyEnum; // can be null: default then will be BinCountBinningStrategy + + + if (binningStrategyEnum != null) { + switch (binningStrategyEnum) { + case bincount: + this.binningStrategy = BinningStrategyFactory.getBinningStrategy(getQueryRange(), (int) binDurationOrBinCount); + break; + case lengthpulse: + case lengthtime: + this.binningStrategy = BinningStrategyFactory.getBinningStrategy(getQueryRange(), binDurationOrBinCount); + break; + default: + logger.warn("No binning strategy has been set. Selecting BinningStrategyBinCount."); + this.binningStrategy = BinningStrategyFactory.getBinningStrategy(getQueryRange(), (int) binDurationOrBinCount); + } + } else { + this.binningStrategy = BinningStrategyFactory.getBinningStrategy(getQueryRange(), (int) binDurationOrBinCount); + } } - + /** * {@inheritDoc} */ @@ -95,7 +129,7 @@ public abstract class AbstractQuery implements Query { public Ordering getOrdering() { return ordering; } - + /** * {@inheritDoc} */ @@ -103,17 +137,20 @@ public abstract class AbstractQuery implements Query { public AggregationType getAggregationType() { return aggregationType; } - - @Override - public BinIntervalCalculator getBinIntervalCalculator() { - // TODO - return null; - } - + + public boolean isAggregateChannels() { return aggregateChannels; } + public BinningStrategyEnum getBinningStrategyEnum() { + return binningStrategyEnum; + } + + @Override + public BinningStrategy getBinningStrategy() { + return binningStrategy; + } public LinkedHashSet getFields() { return fields; @@ -123,6 +160,18 @@ public abstract class AbstractQuery implements Query { return aggregations; } + /** + * {@inheritDoc} + */ + @Override + public QueryRange getQueryRange() { + return queryRange; + } + + public void setQueryRange(QueryRange queryRange) { + this.queryRange = queryRange; + } + @Override public String toString() { return ReflectionToStringBuilder.reflectionToString(this); diff --git a/src/main/java/ch/psi/daq/rest/queries/BinningStrategyEnum.java b/src/main/java/ch/psi/daq/rest/queries/BinningStrategyEnum.java new file mode 100644 index 0000000..9eda782 --- /dev/null +++ b/src/main/java/ch/psi/daq/rest/queries/BinningStrategyEnum.java @@ -0,0 +1,13 @@ +package ch.psi.daq.rest.queries; + +import ch.psi.daq.hazelcast.query.bin.BinningStrategy; + +/** + * Defines the strategies that map to the similarly named {@link BinningStrategy} implementations. + *

+ * This enum is used for type-safety and simplicity for the rest interface. + * + */ +public enum BinningStrategyEnum { + lengthpulse, lengthtime, bincount +} diff --git a/src/main/java/ch/psi/daq/rest/queries/PulseRangeQuery.java b/src/main/java/ch/psi/daq/rest/queries/PulseRangeQuery.java index baf3d18..ba8f9f1 100644 --- a/src/main/java/ch/psi/daq/rest/queries/PulseRangeQuery.java +++ b/src/main/java/ch/psi/daq/rest/queries/PulseRangeQuery.java @@ -18,9 +18,6 @@ import com.fasterxml.jackson.annotation.JsonProperty; */ public class PulseRangeQuery extends AbstractQuery { - private long startPulseId; - private long endPulseId; - @JsonCreator public PulseRangeQuery( // note that those annotations are needed for the polymorphic @@ -28,33 +25,16 @@ public class PulseRangeQuery extends AbstractQuery { @JsonProperty(value = "ordering") Ordering ordering, @JsonProperty(value = "channels") List channels, @JsonProperty(value = "fields") LinkedHashSet fields, + @JsonProperty(value = "binningStrategy") BinningStrategyEnum binningStrategyEnum, + @JsonProperty(value = "binDuration") long binDurationOrBinCount, @JsonProperty(value = "aggregateChannels") boolean aggregateChannels, @JsonProperty(value = "aggregationType") AggregationType aggregationType, @JsonProperty(value = "aggregations") List aggregations, - @JsonProperty(value = "startPulseId") long startPulseId, - @JsonProperty(value = "endPulseId") long endPulseId) - { + @JsonProperty(value = "queryRange") QueryRange queryRange) { - super(ordering, channels, fields, aggregateChannels, aggregationType, aggregations); + super(ordering, channels, fields, binningStrategyEnum, binDurationOrBinCount, aggregateChannels, aggregationType, + aggregations, queryRange); - this.startPulseId = startPulseId; - this.endPulseId = endPulseId; - } - - public long getStartPulseId() { - return startPulseId; - } - - public void setStartPulseId(long startPulseId) { - this.startPulseId = startPulseId; - } - - public long getEndPulseId() { - return endPulseId; - } - - public void setEndPulseId(long endPulseId) { - this.endPulseId = endPulseId; } /** @@ -65,10 +45,4 @@ public class PulseRangeQuery extends AbstractQuery { return ToStringBuilder.reflectionToString(this); } - @Override - public QueryRange getQueryRange() { - // TODO Auto-generated method stub - return null; - } - } diff --git a/src/main/java/ch/psi/daq/rest/queries/TimeRangeQuery.java b/src/main/java/ch/psi/daq/rest/queries/TimeRangeQuery.java index abddaf1..45404bf 100644 --- a/src/main/java/ch/psi/daq/rest/queries/TimeRangeQuery.java +++ b/src/main/java/ch/psi/daq/rest/queries/TimeRangeQuery.java @@ -6,8 +6,6 @@ import java.util.Date; import java.util.LinkedHashSet; import java.util.List; -import javax.validation.constraints.NotNull; - import org.apache.commons.lang.builder.ToStringBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -23,31 +21,24 @@ import com.fasterxml.jackson.annotation.JsonProperty; public class TimeRangeQuery extends AbstractQuery { - private static final String DATE_FORMAT_STRING = "yyyy/MM/dd hh:mm:ss.SSS"; + public static final String DATE_FORMAT_STRING = "yyyy/MM/dd hh:mm:ss.SSS"; private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat(DATE_FORMAT_STRING); private static Logger logger = LoggerFactory.getLogger(TimeRangeQuery.class); - @NotNull - private long start; - @NotNull - private long startNanoOffset; - - @NotNull - private long end; - @NotNull - private long endNanoOffset; - - /** * - * @param ordering + * @param ordering whether to add a 'orderBy' clause into the database query * @param channelIds all the sourceIds (channel names) we want to query * @param fields the fields (who map to fields in the DB) we are interested in returning to the * client, needs to be in insertion order (hence the {@link LinkedHashSet} type) - * @param startMillis - * @param startNanoOffset - * @param endMillis - * @param endNanoOffset + * @param binningStrategyEnum + * @param binDurationOrBinCount + * @param aggregateChannels + * @param aggregationType + * @param aggregations + * @param queryRange + * @param startDateTime + * @param endDateTime */ @JsonCreator public TimeRangeQuery( @@ -56,32 +47,24 @@ public class TimeRangeQuery extends AbstractQuery { @JsonProperty(value = "ordering") Ordering ordering, @JsonProperty(value = "channels") List channels, @JsonProperty(value = "fields") LinkedHashSet fields, + @JsonProperty(value = "binningStrategy") BinningStrategyEnum binningStrategyEnum, + @JsonProperty(value = "binDuration") long binDurationOrBinCount, @JsonProperty(value = "aggregateChannels") boolean aggregateChannels, @JsonProperty(value = "aggregationType") AggregationType aggregationType, @JsonProperty(value = "aggregations") List aggregations, - @JsonProperty(value = "start") long startMillis, - @JsonProperty(value = "startNanoOffset") long startNanoOffset, + @JsonProperty(value = "queryRange") QueryRange queryRange, @JsonProperty(value = "startDateTime") String startDateTime, - @JsonProperty(value = "end") long endMillis, - @JsonProperty(value = "endNanoOffset") long endNanoOffset, @JsonProperty(value = "endDateTime") String endDateTime) { - super(ordering, channels, fields, aggregateChannels, aggregationType, aggregations); - - this.start = startMillis; - this.startNanoOffset = startNanoOffset; - this.end = endMillis; - this.endNanoOffset = endNanoOffset; - - + super(ordering, channels, fields, binningStrategyEnum, binDurationOrBinCount, aggregateChannels, aggregationType, aggregations, queryRange); + if (startDateTime != null && endDateTime != null) { logger.info("startDateTime and endDateTime specified. This takes precedence over the start / end fields."); try { Date startDate = DATE_FORMAT.parse(startDateTime); Date endDate = DATE_FORMAT.parse(endDateTime); - this.start = startDate.getTime(); - this.end = endDate.getTime(); + getQueryRange().setTimeRange(startDate.getTime(), queryRange.getStartNanos(), endDate.getTime(), queryRange.getEndNanos()); } catch (ParseException e) { logger.error("Parsing the start- and/or endDate was unsuccessful. " + "The format must be '" + DATE_FORMAT_STRING + "'", e); @@ -90,38 +73,6 @@ public class TimeRangeQuery extends AbstractQuery { } - public long getStart() { - return start; - } - - public void setStart(long start) { - this.start = start; - } - - public long getStartNanoOffset() { - return startNanoOffset; - } - - public void setStartNanoOffset(long startNanoOffset) { - this.startNanoOffset = startNanoOffset; - } - - public long getEnd() { - return end; - } - - public void setEnd(long end) { - this.end = end; - } - - public long getEndNanoOffset() { - return endNanoOffset; - } - - public void setEndNanoOffset(long endNanoOffset) { - this.endNanoOffset = endNanoOffset; - } - /** * {@inheritDoc} */ @@ -130,11 +81,4 @@ public class TimeRangeQuery extends AbstractQuery { return ToStringBuilder.reflectionToString(this); } - @Override - public QueryRange getQueryRange() { - // TODO Auto-generated method stub - return null; - } - - } diff --git a/src/test/java/ch/psi/daq/test/rest/AbstractDaqRestTest.java b/src/test/java/ch/psi/daq/test/rest/AbstractDaqRestTest.java index 70838af..583bbce 100644 --- a/src/test/java/ch/psi/daq/test/rest/AbstractDaqRestTest.java +++ b/src/test/java/ch/psi/daq/test/rest/AbstractDaqRestTest.java @@ -37,7 +37,8 @@ public abstract class AbstractDaqRestTest { protected MockMvc mockMvc; - protected ObjectMapper mapper = new ObjectMapper(); + @Autowired + protected ObjectMapper mapper; @Before public void setup() { diff --git a/src/test/java/ch/psi/daq/test/rest/DaqRestApplicationConfiguration.java b/src/test/java/ch/psi/daq/test/rest/DaqRestApplicationConfiguration.java index b9def01..0a49467 100644 --- a/src/test/java/ch/psi/daq/test/rest/DaqRestApplicationConfiguration.java +++ b/src/test/java/ch/psi/daq/test/rest/DaqRestApplicationConfiguration.java @@ -5,6 +5,7 @@ import org.springframework.context.annotation.Import; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; +import ch.psi.daq.rest.DaqRestConfiguration; import ch.psi.daq.test.cassandra.LocalCassandraTestConfig; @Configuration @@ -15,7 +16,7 @@ import ch.psi.daq.test.cassandra.LocalCassandraTestConfig; // "ch.psi.daq.cassandra.reader", // "ch.psi.daq.cassandra.writer" //}) -@Import(value = {LocalCassandraTestConfig.class}) +@Import(value = {LocalCassandraTestConfig.class, DaqRestConfiguration.class}) @EnableWebMvc public class DaqRestApplicationConfiguration extends WebMvcConfigurationSupport { diff --git a/src/test/java/ch/psi/daq/test/rest/controller/DaqControllerTest.java b/src/test/java/ch/psi/daq/test/rest/controller/DaqControllerTest.java index bd8e22f..7f03c31 100644 --- a/src/test/java/ch/psi/daq/test/rest/controller/DaqControllerTest.java +++ b/src/test/java/ch/psi/daq/test/rest/controller/DaqControllerTest.java @@ -12,10 +12,14 @@ import org.springframework.test.web.servlet.result.MockMvcResultMatchers; import ch.psi.daq.cassandra.reader.Ordering; import ch.psi.daq.hazelcast.query.AggregationType; +import ch.psi.daq.hazelcast.query.range.QueryRange; +import ch.psi.daq.hazelcast.query.range.QueryRangeImpl; +import ch.psi.daq.rest.queries.BinningStrategyEnum; import ch.psi.daq.rest.queries.PulseRangeQuery; import ch.psi.daq.rest.queries.TimeRangeQuery; import ch.psi.daq.test.rest.AbstractDaqRestTest; +import com.fasterxml.jackson.core.JsonProcessingException; import com.google.common.collect.Lists; import com.google.common.collect.Sets; @@ -28,16 +32,17 @@ public class DaqControllerTest extends AbstractDaqRestTest { @Test public void testPulseRangeQuery() throws Exception { + QueryRange range = new QueryRangeImpl(100l, 101l); PulseRangeQuery request = new PulseRangeQuery( - Ordering.DESC, - Lists.newArrayList(), // DummyQueryProcessor simply returns a fixed list - Sets.newLinkedHashSet(DEFAULT_PROPERTIES), + Ordering.DESC, //ordering + Lists.newArrayList(), // channels, DummyQueryProcessor simply returns a fixed list + Sets.newLinkedHashSet(DEFAULT_PROPERTIES), // fields + BinningStrategyEnum.bincount, + 100, false, AggregationType.index, null, - 100l, - 101l - ); + range); String content = mapper.writeValueAsString(request); @@ -59,18 +64,18 @@ public class DaqControllerTest extends AbstractDaqRestTest { long startTime = new Date().getTime(); long endTime = startTime + TimeUnit.SECONDS.toMillis(1); + QueryRange range = new QueryRangeImpl(startTime, 0, endTime, 0); TimeRangeQuery request = new TimeRangeQuery( Ordering.ASC, - Lists.newArrayList(), // DummyQueryProcessor simply returns a fixed list + Lists.newArrayList("test"), Sets.newLinkedHashSet(DEFAULT_PROPERTIES), + BinningStrategyEnum.bincount, + 100, false, AggregationType.index, null, // aggregations - startTime, // startMillis - 0, - null, - endTime, - 0, + range, + null, // startMillis null); String content = mapper.writeValueAsString(request); @@ -87,4 +92,26 @@ public class DaqControllerTest extends AbstractDaqRestTest { .andExpect(MockMvcResultMatchers.jsonPath("$[0]").exists()) .andExpect(MockMvcResultMatchers.jsonPath("$[0].channel").value("testChannel1")); } + + @Test + public void testMapper() throws JsonProcessingException { + long startTime = new Date().getTime(); + long endTime = startTime + TimeUnit.SECONDS.toMillis(1); + QueryRange range = new QueryRangeImpl(startTime, 0, endTime, 0); + TimeRangeQuery request = new TimeRangeQuery( + Ordering.ASC, + Lists.newArrayList("test"), + Sets.newLinkedHashSet(DEFAULT_PROPERTIES), + BinningStrategyEnum.bincount, + 100, + false, + AggregationType.index, + null, // aggregations + range, + null, // startMillis + null); + + String content = mapper.writeValueAsString(request); + System.out.println(content); + } } diff --git a/src/test/java/ch/psi/daq/test/rest/queries/AbstractQueryTest.java b/src/test/java/ch/psi/daq/test/rest/queries/AbstractQueryTest.java new file mode 100644 index 0000000..4dcd7a5 --- /dev/null +++ b/src/test/java/ch/psi/daq/test/rest/queries/AbstractQueryTest.java @@ -0,0 +1,15 @@ +package ch.psi.daq.test.rest.queries; + +import java.util.Date; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import com.google.common.collect.Lists; + +public class AbstractQueryTest { + + protected static final List DEFAULT_PROPERTIES = Lists.newArrayList("channel", "pulseId"); + + protected long startMillis = new Date().getTime(); + protected long endMillis = new Date().getTime() + TimeUnit.SECONDS.toMillis(10); +} diff --git a/src/test/java/ch/psi/daq/test/rest/queries/AbstractQueryTestTest.java b/src/test/java/ch/psi/daq/test/rest/queries/AbstractQueryTestTest.java new file mode 100644 index 0000000..869c842 --- /dev/null +++ b/src/test/java/ch/psi/daq/test/rest/queries/AbstractQueryTestTest.java @@ -0,0 +1,164 @@ +package ch.psi.daq.test.rest.queries; + +import java.util.Date; +import java.util.concurrent.TimeUnit; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; + +import ch.psi.daq.cassandra.reader.Ordering; +import ch.psi.daq.hazelcast.query.AggregationType; +import ch.psi.daq.hazelcast.query.bin.BinningStrategyBinCount; +import ch.psi.daq.hazelcast.query.bin.BinningStrategyLengthPulse; +import ch.psi.daq.hazelcast.query.bin.BinningStrategyLengthTime; +import ch.psi.daq.hazelcast.query.range.QueryRange; +import ch.psi.daq.hazelcast.query.range.QueryRangeImpl; +import ch.psi.daq.rest.queries.BinningStrategyEnum; +import ch.psi.daq.rest.queries.TimeRangeQuery; + +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; + +@RunWith(BlockJUnit4ClassRunner.class) +public class AbstractQueryTestTest extends AbstractQueryTest { + + @Test(expected=IllegalArgumentException.class) + public void test_NoChannels_exception() { + + long startMillis = new Date().getTime(); + long endMillis = new Date().getTime() + TimeUnit.SECONDS.toMillis(10); + + QueryRange range = new QueryRangeImpl(startMillis, 0, endMillis, 0); + + new TimeRangeQuery( + Ordering.ASC, + null, // should throw exception + Sets.newLinkedHashSet(DEFAULT_PROPERTIES), + BinningStrategyEnum.bincount, + 100, // binDurationOrBincount : long + false, // isAggregateChannels + AggregationType.index, + null, // list of aggregations + range, + null, // startDateTime : String + null); // endDateTime : String + + } + + @Test(expected=IllegalArgumentException.class) + public void test_NoFields_exception() { + + long startMillis = new Date().getTime(); + long endMillis = new Date().getTime() + TimeUnit.SECONDS.toMillis(10); + QueryRange range = new QueryRangeImpl(startMillis, 0, endMillis, 0); + + new TimeRangeQuery( + Ordering.ASC, + Lists.newArrayList(), + null, + BinningStrategyEnum.bincount, + 100, // binDurationOrBincount : long + false, // isAggregateChannels + AggregationType.index, + null, // list of aggregations + range, + null, // startDateTime : String + null); // endDateTime : String + + } + + @Test + public void test_nullBinningStrategyEnum_exception() { + + long startMillis = new Date().getTime(); + long endMillis = new Date().getTime() + TimeUnit.SECONDS.toMillis(10); + QueryRange range = new QueryRangeImpl(startMillis, 0, endMillis, 0); + TimeRangeQuery query = new TimeRangeQuery( + Ordering.ASC, + Lists.newArrayList(), + Sets.newLinkedHashSet(DEFAULT_PROPERTIES), + null, + 100, // binDurationOrBincount : long + false, // isAggregateChannels + AggregationType.index, + null, // list of aggregations + range, + null, // startDateTime : String + null); // endDateTime : String + + Assert.assertTrue(query.getBinningStrategy() != null); + Assert.assertEquals(BinningStrategyBinCount.class, query.getBinningStrategy().getClass()); + } + + @Test + public void test_LengthBinningTimeStrategy() { + + long startMillis = new Date().getTime(); + long endMillis = new Date().getTime() + TimeUnit.SECONDS.toMillis(10); + QueryRange range = new QueryRangeImpl(startMillis, 0, endMillis, 0); + TimeRangeQuery query = new TimeRangeQuery( + Ordering.ASC, + Lists.newArrayList(), + Sets.newLinkedHashSet(DEFAULT_PROPERTIES), + BinningStrategyEnum.lengthpulse, + 100, // binDurationOrBincount : long + false, // isAggregateChannels + AggregationType.index, + null, // list of aggregations + range, + null, // startDateTime : String + null); // endDateTime : String + + Assert.assertTrue(query.getBinningStrategy() != null); + Assert.assertEquals(BinningStrategyLengthTime.class, query.getBinningStrategy().getClass()); + } + + @Test + public void test_LengthBinningPulseStrategy() { + + long startPulse = 100l; + long endPulse = 105l; + QueryRange range = new QueryRangeImpl(startPulse, endPulse); + TimeRangeQuery query = new TimeRangeQuery( + Ordering.ASC, + Lists.newArrayList(), + Sets.newLinkedHashSet(DEFAULT_PROPERTIES), + BinningStrategyEnum.lengthpulse, + 100, // binDurationOrBincount : long + false, // isAggregateChannels + AggregationType.index, + null, // list of aggregations + range, + null, // startDateTime : String + null); // endDateTime : String + + Assert.assertTrue(query.getBinningStrategy() != null); + Assert.assertEquals(BinningStrategyLengthPulse.class, query.getBinningStrategy().getClass()); + } + + @Test + public void test_BinCountBinningStrategy() { + + long startMillis = new Date().getTime(); + long endMillis = new Date().getTime() + TimeUnit.SECONDS.toMillis(10); + QueryRange range = new QueryRangeImpl(startMillis, 0, endMillis, 0); + TimeRangeQuery query = new TimeRangeQuery( + Ordering.ASC, + Lists.newArrayList(), + Sets.newLinkedHashSet(DEFAULT_PROPERTIES), + BinningStrategyEnum.bincount, + 100, // binDurationOrBincount : long + false, // isAggregateChannels + AggregationType.index, + null, // list of aggregations + range, + null, // startDateTime : String + null); // endDateTime : String + + Assert.assertTrue(query.getBinningStrategy() != null); + Assert.assertEquals(BinningStrategyBinCount.class, query.getBinningStrategy().getClass()); + } + +} diff --git a/src/test/java/ch/psi/daq/test/rest/queries/TimeRangeQueryTest.java b/src/test/java/ch/psi/daq/test/rest/queries/TimeRangeQueryTest.java new file mode 100644 index 0000000..ba0334f --- /dev/null +++ b/src/test/java/ch/psi/daq/test/rest/queries/TimeRangeQueryTest.java @@ -0,0 +1,73 @@ +package ch.psi.daq.test.rest.queries; + +import java.text.ParseException; +import java.text.SimpleDateFormat; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.BlockJUnit4ClassRunner; + +import ch.psi.daq.cassandra.reader.Ordering; +import ch.psi.daq.hazelcast.query.AggregationType; +import ch.psi.daq.hazelcast.query.range.QueryRange; +import ch.psi.daq.hazelcast.query.range.QueryRangeImpl; +import ch.psi.daq.rest.queries.BinningStrategyEnum; +import ch.psi.daq.rest.queries.TimeRangeQuery; + +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; + +@RunWith(BlockJUnit4ClassRunner.class) +public class TimeRangeQueryTest extends AbstractQueryTest { + + @Test + public void test_startAndEndDateTime_asString() throws ParseException { + + // allowed format: yyyy/MM/dd hh:mm:ss.SSS + String startDateTime = "2014/01/01 12:00:00.000"; + String endDateTime = "2014/01/01 18:00:00.000"; + + QueryRange range = new QueryRangeImpl(-1, 0, -1, 0); + + TimeRangeQuery query = new TimeRangeQuery( + Ordering.ASC, + Lists.newArrayList(), // DummyQueryProcessor simply returns a fixed list + Sets.newLinkedHashSet(DEFAULT_PROPERTIES), + BinningStrategyEnum.bincount, + 100, // binDurationOrBincount : long + false, // isAggregateChannels + AggregationType.index, + null, // list of aggregations + range, + startDateTime, // startDateTime : String + endDateTime); // endDateTime : String + + SimpleDateFormat format = new SimpleDateFormat(TimeRangeQuery.DATE_FORMAT_STRING); + + Assert.assertEquals(format.parse(startDateTime).getTime(), query.getQueryRange().getStartMillis()); + Assert.assertEquals(format.parse(endDateTime).getTime(), query.getQueryRange().getEndMillis()); + } + + @Test + public void test_wrongFormat_exception() { + String startDateTime = "2014-01-01 12:00:00.000"; + String endDateTime = "2014/01/01 18:00:00.000"; + QueryRange range = new QueryRangeImpl(-1, 0, -1, 0); + TimeRangeQuery query = new TimeRangeQuery( + Ordering.ASC, + Lists.newArrayList(), // DummyQueryProcessor simply returns a fixed list + Sets.newLinkedHashSet(DEFAULT_PROPERTIES), + BinningStrategyEnum.bincount, + 100, // binDurationOrBincount : long + false, // isAggregateChannels + AggregationType.index, + null, + range, + startDateTime, // startDateTime : String + endDateTime); // endDateTime : String + + Assert.assertEquals(-1, query.getQueryRange().getStartMillis()); + Assert.assertEquals(-1, query.getQueryRange().getStartMillis()); + } +} diff --git a/src/test/resources/test-requests.txt b/src/test/resources/test-requests.txt index b5af79d..27980d2 100644 --- a/src/test/resources/test-requests.txt +++ b/src/test/resources/test-requests.txt @@ -6,8 +6,10 @@ "test2" ], "fields": [ - "channel", pulseId", "globalMillis", "globalNanos", "dbValueBytes" + "channel", "pulseId", "globalMillis", "globalNanos", "dbValueBytes" ], + "binningStrategy" : "bincount", + "binDuration" : 100, "aggregateChannels":"false", "aggregationType": "index", "aggregations": [ @@ -25,7 +27,7 @@ "endPulseId" : 200 } -curl -v -X POST -H 'Content-Type: application/json' -d '{"queryType":"pulserange","ordering":"ASC","channels":["test1","test2"],"fields":["channel","pulseId"],"aggregateChannels":"false","aggregationType":"index","aggregations":[{"fieldRef":"e_val","type":"max","resultFieldName":"maximum"},{"fieldRef":"e_val","type":"min","resultFieldName":"minimum"}],"startPulseId":100,"endPulseId":200}' http://localhost:8080/pulserange +curl -v -X POST -H 'Content-Type: application/json' -d '{"queryType":"pulserange","ordering":"ASC","channels":["test1","test2"],"fields":["channel","pulseId","globalMillis","globalNanos","dbValueBytes"],"binningStrategy":"bincount","binDuration":100,"aggregateChannels":"false","aggregationType":"index","aggregations":[{"fieldRef":"e_val","type":"max","resultFieldName":"maximum"},{"fieldRef":"e_val","type":"min","resultFieldName":"minimum"}],"startPulseId":100,"endPulseId":200}' http://localhost:8080/pulserange =============================================================================================================================================== @@ -40,15 +42,21 @@ curl -v -X POST -H 'Content-Type: application/json' -d '{"queryType":"pulserange "channel", "pulseId" ], + "binningStrategy" : "duration", + "binDuration" : 100, "aggregateChannels":false, + "aggregationType": "index", "aggregations":null, "start":1434717654177, "startNanoOffset":0, "end":1434717655177, "endNanoOffset":0, - "valueAggregation":"index", - "binIntervalCalculator":null, "ordering":"DESC" } -curl -v -X POST -H 'Content-Type: application/json' -d '{"queryType":"timerange","channels":["test1","test2"],"fields":["channel","pulseId"],"aggregateChannels":false,"aggregations":null,"start":1434717654177,"startNanoOffset":0,"end":1434717655177,"endNanoOffset":0,"valueAggregation":"index","ordering":"ASC"}' http://localhost:8080/timerange \ No newline at end of file +curl -v -X POST -H 'Content-Type: application/json' -d '{"queryType":"timerange","channels":["test1","test2"],"fields":["channel","pulseId"],"binningStrategy":"duration","binDuration":100,"aggregateChannels":false,"aggregations":null,"start":1434717654177,"startNanoOffset":0,"end":1434717655177,"endNanoOffset":0,"aggregationType":"index","ordering":"DESC"}' http://localhost:8080/timerange + +curl -v -X POST -H 'Content-Type: application/json' -d '{"queryType":"timerange","ordering":"ASC","channels":["test"],"fields":["channel","pulseId"],"binningStrategy":{"combinedMarkerCalculator":{}},"aggregateChannels":false,"aggregationType":"index","queryRange":{"startMillis":1435048390294,"startNanos":0,"endMillis":1435048391294,"endNanos":0,"startPulseId":9223372036854775807,"endPulseId":9223372036854775807},"binningStrategyEnum":"bincount"}' http://localhost:8080/timerange + +curl -v -X POST -H 'Content-Type: application/json' -d '{"queryType":"timerange","ordering":"ASC","channels":["test"],"fields":["channel","pulseId"],"aggregateChannels":false,"aggregationType":"index","queryRange":{"startMillis":1435049709091,"startNanos":0,"endMillis":1435049710091,"endNanos":0,"startPulseId":9223372036854775807,"endPulseId":9223372036854775807},"binningStrategyEnum":"bincount"}' http://localhost:8080/timerange + From 6d44da8c96a7ddbdb4eb71ead9469ed6c4b2d213 Mon Sep 17 00:00:00 2001 From: Zellweger Christof Ralf Date: Tue, 23 Jun 2015 15:50:03 +0200 Subject: [PATCH 2/2] ATEST-81: - added dummy write method for REST interface --- .../ch/psi/daq/rest/DaqRestConfiguration.java | 12 ++++++-- .../ch/psi/daq/rest/DaqRestController.java | 28 +++++++++++++++++-- .../ch/psi/daq/rest/ResponseStreamWriter.java | 5 +--- ...erTest.java => DaqRestControllerTest.java} | 2 +- src/test/resources/test-requests.txt | 4 +++ 5 files changed, 42 insertions(+), 9 deletions(-) rename src/test/java/ch/psi/daq/test/rest/controller/{DaqControllerTest.java => DaqRestControllerTest.java} (98%) diff --git a/src/main/java/ch/psi/daq/rest/DaqRestConfiguration.java b/src/main/java/ch/psi/daq/rest/DaqRestConfiguration.java index 799c52d..027cc69 100644 --- a/src/main/java/ch/psi/daq/rest/DaqRestConfiguration.java +++ b/src/main/java/ch/psi/daq/rest/DaqRestConfiguration.java @@ -3,11 +3,13 @@ package ch.psi.daq.rest; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import ch.psi.daq.cassandra.writer.CassandraWriter; +import ch.psi.daq.cassandra.writer.CassandraWriterImpl; import ch.psi.daq.common.statistic.StorelessStatistics; import ch.psi.daq.domain.cassandra.ChannelEvent; import ch.psi.daq.hazelcast.query.processor.QueryProcessor; +import ch.psi.daq.hazelcast.query.processor.cassandra.CassandraQueryProcessorLocal; import ch.psi.daq.rest.model.PropertyFilterMixin; -import ch.psi.daq.test.rest.query.DummyQueryProcessor; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.core.JsonFactory; @@ -18,9 +20,15 @@ public class DaqRestConfiguration { @Bean public QueryProcessor queryProcessor() { - return new DummyQueryProcessor(); +// return new DummyQueryProcessor(); + return new CassandraQueryProcessorLocal(); } + @Bean + public CassandraWriter cassandraWriter() { + return new CassandraWriterImpl(); + } + @Bean public JsonFactory jsonFactory() { return new JsonFactory(); diff --git a/src/main/java/ch/psi/daq/rest/DaqRestController.java b/src/main/java/ch/psi/daq/rest/DaqRestController.java index b5e18c0..5d14b55 100644 --- a/src/main/java/ch/psi/daq/rest/DaqRestController.java +++ b/src/main/java/ch/psi/daq/rest/DaqRestController.java @@ -2,6 +2,8 @@ package ch.psi.daq.rest; import java.io.IOException; import java.util.Map; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; import java.util.stream.Stream; import javax.servlet.http.HttpServletResponse; @@ -13,6 +15,8 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import ch.psi.daq.cassandra.writer.CassandraWriter; +import ch.psi.daq.domain.cassandra.ChannelEvent; import ch.psi.daq.domain.cassandra.DataEvent; import ch.psi.daq.hazelcast.query.processor.QueryProcessor; import ch.psi.daq.rest.queries.AbstractQuery; @@ -23,11 +27,13 @@ import ch.psi.daq.rest.queries.TimeRangeQuery; public class DaqRestController { private static final Logger logger = LoggerFactory.getLogger(DaqRestController.class); - + + @Autowired + private CassandraWriter cassandraWriter; + @Autowired private ResponseStreamWriter responseStreamWriter; - // TODO: just a dummy test implementation - remove when the real processor is ready @Autowired private QueryProcessor queryProcessor; @@ -67,6 +73,7 @@ public class DaqRestController { * @throws IOException */ private void executeQuery(AbstractQuery query, HttpServletResponse res) throws IOException { + // all the magic happens here Map> process = queryProcessor.process(query); @@ -77,4 +84,21 @@ public class DaqRestController { // write the response back to the client using java 8 streams responseStreamWriter.respond(flatStreams, query, res); } + + + @RequestMapping(value = "/write") + public void writeDummyEntry() { + int pulseId = 100; + ChannelEvent event = new ChannelEvent( + "dummy-test", + pulseId, + 0, + pulseId, + pulseId, + 0, + "data_" + UUID.randomUUID().toString()); + + CompletableFuture future = cassandraWriter.writeAsync(3, 0, event); + future.join(); + } } diff --git a/src/main/java/ch/psi/daq/rest/ResponseStreamWriter.java b/src/main/java/ch/psi/daq/rest/ResponseStreamWriter.java index e9847c1..2d0efd5 100644 --- a/src/main/java/ch/psi/daq/rest/ResponseStreamWriter.java +++ b/src/main/java/ch/psi/daq/rest/ResponseStreamWriter.java @@ -57,12 +57,9 @@ public class ResponseStreamWriter { .stream() .map(a -> { return a.getType().toString(); - }) - .collect(Collectors.toSet())); + }).collect(Collectors.toSet())); } - ObjectWriter writer = configureWriter(includedFields); - respondInternal(stream, response, writer); } diff --git a/src/test/java/ch/psi/daq/test/rest/controller/DaqControllerTest.java b/src/test/java/ch/psi/daq/test/rest/controller/DaqRestControllerTest.java similarity index 98% rename from src/test/java/ch/psi/daq/test/rest/controller/DaqControllerTest.java rename to src/test/java/ch/psi/daq/test/rest/controller/DaqRestControllerTest.java index 7f03c31..9708af6 100644 --- a/src/test/java/ch/psi/daq/test/rest/controller/DaqControllerTest.java +++ b/src/test/java/ch/psi/daq/test/rest/controller/DaqRestControllerTest.java @@ -26,7 +26,7 @@ import com.google.common.collect.Sets; /** * Tests the {@link DaqController} implementation. */ -public class DaqControllerTest extends AbstractDaqRestTest { +public class DaqRestControllerTest extends AbstractDaqRestTest { private static final List DEFAULT_PROPERTIES = Lists.newArrayList("channel", "pulseId"); diff --git a/src/test/resources/test-requests.txt b/src/test/resources/test-requests.txt index 27980d2..0262784 100644 --- a/src/test/resources/test-requests.txt +++ b/src/test/resources/test-requests.txt @@ -60,3 +60,7 @@ curl -v -X POST -H 'Content-Type: application/json' -d '{"queryType":"timerange" curl -v -X POST -H 'Content-Type: application/json' -d '{"queryType":"timerange","ordering":"ASC","channels":["test"],"fields":["channel","pulseId"],"aggregateChannels":false,"aggregationType":"index","queryRange":{"startMillis":1435049709091,"startNanos":0,"endMillis":1435049710091,"endNanos":0,"startPulseId":9223372036854775807,"endPulseId":9223372036854775807},"binningStrategyEnum":"bincount"}' http://localhost:8080/timerange + + + +curl -v -X POST -H 'Content-Type: application/json' -d '{"queryType":"pulserange","ordering":"ASC","channels":["dummy-test"],"fields":["channel","pulseId","globalMillis","globalNanos","dbValueBytes"],"binningStrategy":"bincount","binDuration":100,"aggregateChannels":"false","aggregationType":"index","aggregations":[{"fieldRef":"e_val","type":"max","resultFieldName":"maximum"},{"fieldRef":"e_val","type":"min","resultFieldName":"minimum"}], "queryRange":{"startPulseId":100,"endPulseId":100}}' http://localhost:8080/pulserange \ No newline at end of file