From 84885412824b54ccba5c4e42919411f0970f37d9 Mon Sep 17 00:00:00 2001 From: Zellweger Christof Ralf Date: Tue, 27 Oct 2015 15:41:42 +0100 Subject: [PATCH 1/6] ATEST-259: - trying to implement dummy cassandra reader - fixing some of the tests --- .../controller/QueryRestController.java | 72 +++++- .../daq/test/queryrest/DaqWebMvcConfig.java | 10 +- .../queryrest/query/DummyCassandraReader.java | 224 ++++++++++++++++++ 3 files changed, 302 insertions(+), 4 deletions(-) create mode 100644 src/test/java/ch/psi/daq/test/queryrest/query/DummyCassandraReader.java diff --git a/src/main/java/ch/psi/daq/queryrest/controller/QueryRestController.java b/src/main/java/ch/psi/daq/queryrest/controller/QueryRestController.java index ab518a7..4abb185 100644 --- a/src/main/java/ch/psi/daq/queryrest/controller/QueryRestController.java +++ b/src/main/java/ch/psi/daq/queryrest/controller/QueryRestController.java @@ -2,9 +2,11 @@ package ch.psi.daq.queryrest.controller; import java.io.IOException; import java.util.Collection; +import java.util.List; import java.util.Map.Entry; import java.util.Set; import java.util.function.Function; +import java.util.stream.Collectors; import java.util.stream.Stream; import javax.annotation.Resource; @@ -27,9 +29,11 @@ import org.springframework.web.bind.annotation.RestController; import ch.psi.daq.cassandra.request.validate.RequestProviderValidator; import ch.psi.daq.cassandra.util.test.CassandraDataGen; import ch.psi.daq.common.json.deserialize.AttributeBasedDeserializer; +import ch.psi.daq.common.ordering.Ordering; import ch.psi.daq.domain.DataEvent; import ch.psi.daq.query.analyzer.QueryAnalyzer; import ch.psi.daq.query.model.Aggregation; +import ch.psi.daq.query.model.AggregationType; import ch.psi.daq.query.model.DBMode; import ch.psi.daq.query.model.Query; import ch.psi.daq.query.model.QueryField; @@ -39,6 +43,8 @@ import ch.psi.daq.queryrest.config.QueryRestConfig; import ch.psi.daq.queryrest.model.ChannelsRequest; import ch.psi.daq.queryrest.response.ResponseStreamWriter; +import com.google.common.collect.Lists; + @RestController public class QueryRestController { @@ -114,6 +120,68 @@ public class QueryRestController { return getChannels(new ChannelsRequest(channelName)); } + + /** + * Returns the current list of {@link Ordering}s available. + * + * @return list of {@link Ordering}s as String array + */ + @RequestMapping(value = "ordering", method = {RequestMethod.GET}, + produces = {MediaType.APPLICATION_JSON_VALUE}) + public @ResponseBody List getOrderingValues() { + List orderings = Lists.newArrayList(Ordering.values()); + return orderings.stream() + .map((Ordering ord) -> { + return ord.toString(); + }).collect(Collectors.toList()); + } + + /** + * Returns the current list of {@link QueryField}s available. + * + * @return list of {@link QueryField}s as String array + */ + @RequestMapping(value = "queryfields", method = {RequestMethod.GET}, + produces = {MediaType.APPLICATION_JSON_VALUE}) + public @ResponseBody List getQueryFieldValues() { + List orderings = Lists.newArrayList(QueryField.values()); + return orderings.stream() + .map((QueryField qf) -> { + return qf.toString(); + }).collect(Collectors.toList()); + } + + /** + * Returns the current list of {@link Aggregation}s available. + * + * @return list of {@link Aggregation}s as String array + */ + @RequestMapping(value = "aggregations", method = {RequestMethod.GET}, + produces = {MediaType.APPLICATION_JSON_VALUE}) + public @ResponseBody List getAggregationsValues() { + List orderings = Lists.newArrayList(Aggregation.values()); + return orderings.stream() + .map((Aggregation value) -> { + return value.toString(); + }).collect(Collectors.toList()); + } + + /** + * Returns the current list of {@link AggregationType}s available. + * + * @return list of {@link AggregationType}s as String array + */ + @RequestMapping(value = "aggregationtypes", method = {RequestMethod.GET}, + produces = {MediaType.APPLICATION_JSON_VALUE}) + public @ResponseBody List getAggregationTypesValues() { + List orderings = Lists.newArrayList(AggregationType.values()); + return orderings.stream() + .map((AggregationType value) -> { + return value.toString(); + }).collect(Collectors.toList()); + } + + /** * Catch-all query method for getting data from the backend. *

@@ -143,8 +211,8 @@ public class QueryRestController { QueryAnalyzer queryAnalizer = queryAnalizerFactory.apply(query); // all the magic happens here - Stream>> channelToDataEvents = getQueryProcessor(query.getDbMode()) - .process(queryAnalizer); + Stream>> channelToDataEvents = + getQueryProcessor(query.getDbMode()).process(queryAnalizer); // do post-process Stream> channelToData = queryAnalizer.postProcess(channelToDataEvents); diff --git a/src/test/java/ch/psi/daq/test/queryrest/DaqWebMvcConfig.java b/src/test/java/ch/psi/daq/test/queryrest/DaqWebMvcConfig.java index 9bc39dd..7b0a34a 100644 --- a/src/test/java/ch/psi/daq/test/queryrest/DaqWebMvcConfig.java +++ b/src/test/java/ch/psi/daq/test/queryrest/DaqWebMvcConfig.java @@ -9,12 +9,14 @@ import org.springframework.context.annotation.PropertySources; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; +import ch.psi.daq.cassandra.reader.CassandraReader; import ch.psi.daq.domain.reader.DataReader; import ch.psi.daq.query.processor.QueryProcessor; import ch.psi.daq.query.processor.QueryProcessorLocal; import ch.psi.daq.test.cassandra.admin.CassandraTestAdmin; import ch.psi.daq.test.cassandra.admin.CassandraTestAdminImpl; import ch.psi.daq.test.query.config.LocalQueryTestConfig; +import ch.psi.daq.test.queryrest.query.DummyCassandraReader; import ch.psi.daq.test.queryrest.query.DummyDataReader; @Configuration @@ -32,8 +34,8 @@ public class DaqWebMvcConfig extends WebMvcConfigurationSupport { } @Bean - public QueryProcessor queryProcessor() { - return new QueryProcessorLocal(new DummyDataReader()); + public QueryProcessor cassandraQueryProcessorLocal() { + return new QueryProcessorLocal(dataReader()); } @Bean @@ -41,6 +43,10 @@ public class DaqWebMvcConfig extends WebMvcConfigurationSupport { return new DummyDataReader(); } + @Bean CassandraReader cassandraReader() { + return new DummyCassandraReader(); + } + @Bean public CassandraTestAdmin cassandraTestAdmin() { return new CassandraTestAdminImpl(); diff --git a/src/test/java/ch/psi/daq/test/queryrest/query/DummyCassandraReader.java b/src/test/java/ch/psi/daq/test/queryrest/query/DummyCassandraReader.java new file mode 100644 index 0000000..a95a2e9 --- /dev/null +++ b/src/test/java/ch/psi/daq/test/queryrest/query/DummyCassandraReader.java @@ -0,0 +1,224 @@ +/** + * + */ +package ch.psi.daq.test.queryrest.query; + +import java.awt.image.MultiPixelPackedSampleModel; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.apache.commons.lang.NotImplementedException; + +import ch.psi.daq.cassandra.reader.CassandraReader; +import ch.psi.daq.cassandra.reader.query.PulseIdRangeQuery; +import ch.psi.daq.cassandra.reader.query.TimeRangeQuery; +import ch.psi.daq.cassandra.util.test.CassandraDataGen; +import ch.psi.daq.common.ordering.Ordering; +import ch.psi.daq.domain.DataEvent; +import ch.psi.daq.domain.cassandra.ChannelEvent; +import ch.psi.daq.domain.cassandra.MetaPulseId; +import ch.psi.daq.domain.cassandra.MetaTime; +import ch.psi.daq.domain.cassandra.querying.ChannelEventQuery; +import ch.psi.daq.domain.cassandra.querying.ChannelEventQueryInfo; +import ch.psi.daq.domain.cassandra.querying.EventQuery; + +import com.google.common.collect.Lists; + +/** + * @author zellweger_c + * + */ +public class DummyCassandraReader implements CassandraReader { + + private static final int KEYSPACE = 1; + private CassandraDataGen dataGen; + private String[] channels; + + + /** + * + */ + public DummyCassandraReader() { + this.dataGen = new CassandraDataGen(); + this.channels = new String[]{ + "testChannel1", + "testChannel2", + "BooleanScalar", + "BooleanWaveform", + "ByteScalar", + "ByteWaveform", + "DoubleScalar", + "DoubleWaveform", + "FloatScalar", + "FloatWaveform", + "IntegerScalar", + "IntegerWaveform", + "LongScalar", + "LongWaveform", + "ShortScalar", + "ShortWaveform", + "StringScalar", + "UByteScalar", + "UByteWaveform", + "UIntegerScalar", + "UIntegerWaveform", + "ULongScalar", + "ULongWaveform", + "UShortScalar", + "UShortWaveform"}; + } + /** + * @{inheritDoc} + */ + @Override + public Stream getChannelStream(String regex) { + return Stream.of(channels); + } + + /** + * @{inheritDoc} + */ + @Override + public Stream getEventStream(String channel, long startPulseId, long endPulseId, + Ordering ordering, String... columns) { + return getDummyEventStream(channel, startPulseId, endPulseId); + } + + /** + * @{inheritDoc} + */ + @Override + public Stream getEventStream(String channel, long startMillis, long startNanos, long endMillis, + long endNanos, Ordering ordering, String... columns) { + return getDummyEventStream(channel, startMillis, endMillis); + } + + /** + * @{inheritDoc} + */ + @Override + public Stream getEventStream(EventQuery eventQuery, Stream queryProviders) { + List result = Lists.newArrayList(); + queryProviders.forEach(ceq -> { + if (ceq instanceof ChannelEventQueryInfo) { + result.add(getEvent((ChannelEventQueryInfo) ceq)); + } else { + throw new NotImplementedException("This is not yet implemented!"); + } + }); + return result.stream(); + } + /** + * @{inheritDoc} + */ + @Override + public Stream getEventStream(PulseIdRangeQuery query) { + Stream dummyEventStream = getDummyEventStream(query.getChannel(), query.getStartPulseId(), query.getEndPulseId()) + .map(ce -> { return (ChannelEvent) ce; }); + return dummyEventStream; + + } + /** + * @{inheritDoc} + */ + @Override + public Stream getEventStream(TimeRangeQuery query) { + Stream dummyEventStream = getDummyEventStream(query.getChannel(), query.getStartMillis(), query.getEndMillis()) + .map(ce -> { return (ChannelEvent) ce; }); + return dummyEventStream; + } + + + private Stream getDummyEventStream(String channel, long startIndex, long endIndex) { + return dataGen.generateData(startIndex, (endIndex-startIndex), channel).stream(); + } + + /** + * @{inheritDoc} + */ + @Override + public List getChannels() { + return Lists.newArrayList(channels); + } + + /** + * @{inheritDoc} + */ + @Override + public List getChannels(String regex) { + return Lists.newArrayList(channels).stream().filter(s -> { return s.contains(regex); }).collect(Collectors.toList()); + } + + /** + * @{inheritDoc} + */ + @Override + public ChannelEvent getEvent(ChannelEventQueryInfo queryInfo, String... columns) { + if (queryInfo.getPulseId() > 0) { + return dataGen.generateData(queryInfo.getPulseId(), 1, queryInfo.getChannel()).get(0); + } + return dataGen.generateData(queryInfo.getGlobalMillis(), 1, queryInfo.getChannel()).get(0); + } + + /** + * @{inheritDoc} + */ + @Override + public CompletableFuture getEventAsync(ChannelEventQueryInfo queryInfo, String... columns) { + throw new NotImplementedException(); + } + + /** + * @{inheritDoc} + */ + @Override + public Stream getChannelEventQueryStream(PulseIdRangeQuery query) { + return dataGen.generateMetaPulseId( + KEYSPACE, + query.getStartPulseId(), + (query.getEndPulseId() - query.getStartPulseId()), + query.getChannel()).stream(); + } + + /** + * @{inheritDoc} + */ + @Override + public Stream getChannelEventQueryStream(TimeRangeQuery query) { + return dataGen.generateMetaTime( + KEYSPACE, + query.getStartMillis(), + (query.getEndMillis() - query.getStartMillis()), + query.getChannel()) + .stream() + .map(e -> { + return (ChannelEventQuery) e; + }); + } + + /** + * @{inheritDoc} + */ + @Override + public Stream getMetaPulseIdStream(PulseIdRangeQuery query) { + return dataGen.generateMetaPulseId( + KEYSPACE, + query.getStartPulseId(), (query.getEndPulseId() - query.getStartPulseId()), + query.getChannel()).stream(); + } + + + /** + * @{inheritDoc} + */ + @Override + public Stream getMetaTimeStream(TimeRangeQuery query) { + return dataGen.generateMetaTime( + KEYSPACE, + query.getStartMillis(), (query.getEndMillis() - query.getStartMillis()), + query.getChannel()).stream(); + } + +} From 001e093623c6f4d055618b392f64686fd587968f Mon Sep 17 00:00:00 2001 From: Zellweger Christof Ralf Date: Tue, 27 Oct 2015 18:00:05 +0100 Subject: [PATCH 2/6] ATEST-259: - fixing QueryRestController tests before adding the CORS filter --- .project | 6 ++ .../daq/test/queryrest/DaqWebMvcConfig.java | 9 +-- .../controller/DaqRestControllerTest.java | 73 ++++++++++--------- .../queryrest/query/DummyCassandraReader.java | 68 ++++++++++++----- 4 files changed, 93 insertions(+), 63 deletions(-) diff --git a/.project b/.project index 56f8001..08328ec 100644 --- a/.project +++ b/.project @@ -5,6 +5,11 @@ + + org.eclipse.wst.common.project.facet.core.builder + + + org.eclipse.jdt.core.javabuilder @@ -20,5 +25,6 @@ org.springframework.ide.eclipse.core.springnature org.springsource.ide.eclipse.gradle.core.nature org.eclipse.jdt.core.javanature + org.eclipse.wst.common.project.facet.core.nature diff --git a/src/test/java/ch/psi/daq/test/queryrest/DaqWebMvcConfig.java b/src/test/java/ch/psi/daq/test/queryrest/DaqWebMvcConfig.java index 7b0a34a..bbfdad5 100644 --- a/src/test/java/ch/psi/daq/test/queryrest/DaqWebMvcConfig.java +++ b/src/test/java/ch/psi/daq/test/queryrest/DaqWebMvcConfig.java @@ -10,14 +10,12 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; import ch.psi.daq.cassandra.reader.CassandraReader; -import ch.psi.daq.domain.reader.DataReader; import ch.psi.daq.query.processor.QueryProcessor; import ch.psi.daq.query.processor.QueryProcessorLocal; import ch.psi.daq.test.cassandra.admin.CassandraTestAdmin; import ch.psi.daq.test.cassandra.admin.CassandraTestAdminImpl; import ch.psi.daq.test.query.config.LocalQueryTestConfig; import ch.psi.daq.test.queryrest.query.DummyCassandraReader; -import ch.psi.daq.test.queryrest.query.DummyDataReader; @Configuration @ComponentScan @@ -35,12 +33,7 @@ public class DaqWebMvcConfig extends WebMvcConfigurationSupport { @Bean public QueryProcessor cassandraQueryProcessorLocal() { - return new QueryProcessorLocal(dataReader()); - } - - @Bean - public DataReader dataReader() { - return new DummyDataReader(); + return new QueryProcessorLocal(cassandraReader()); } @Bean CassandraReader cassandraReader() { diff --git a/src/test/java/ch/psi/daq/test/queryrest/controller/DaqRestControllerTest.java b/src/test/java/ch/psi/daq/test/queryrest/controller/DaqRestControllerTest.java index 3c0ac75..6745580 100644 --- a/src/test/java/ch/psi/daq/test/queryrest/controller/DaqRestControllerTest.java +++ b/src/test/java/ch/psi/daq/test/queryrest/controller/DaqRestControllerTest.java @@ -3,7 +3,6 @@ package ch.psi.daq.test.queryrest.controller; import javax.annotation.Resource; import org.junit.After; -import org.junit.Before; import org.junit.Test; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; @@ -31,20 +30,8 @@ public class DaqRestControllerTest extends AbstractDaqRestTest { @Resource private CassandraDataGen dataGen; - private static final boolean initialized = false; - - private static final int DATA_KEYSPACE = 1; public static final String[] TEST_CHANNEL_NAMES = new String[]{"testChannel1", "testChannel2"}; - @Before - public void setUp() throws Exception { - if (!initialized) { - cassandraTestAdmin.truncateAll(); - - dataGen.writeData(DATA_KEYSPACE, 100, 2, TEST_CHANNEL_NAMES); - } - } - @After public void tearDown() throws Exception {} @@ -59,10 +46,26 @@ public class DaqRestControllerTest extends AbstractDaqRestTest { .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.jsonPath("$").isArray()) .andExpect(MockMvcResultMatchers.jsonPath("$[0]").exists()) - .andExpect(MockMvcResultMatchers.jsonPath("$[0]").value("testChannel1")) - .andExpect(MockMvcResultMatchers.jsonPath("$[1]").exists()) - .andExpect(MockMvcResultMatchers.jsonPath("$[1]").value("testChannel2")) - .andExpect(MockMvcResultMatchers.jsonPath("$[2]").doesNotExist()); + .andExpect(MockMvcResultMatchers.jsonPath("$[0]").value("BooleanScalar")) + .andExpect(MockMvcResultMatchers.jsonPath("$[1]").value("BooleanWaveform")); + + } + + @Test + public void testSpecificChannelSearch() throws Exception { + this.mockMvc.perform( + MockMvcRequestBuilders + .get(QueryRestController.CHANNELS + "/integer") + .contentType(MediaType.APPLICATION_JSON)) + .andDo(MockMvcResultHandlers.print()) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$").isArray()) + .andExpect(MockMvcResultMatchers.jsonPath("$[0]").exists()) + .andExpect(MockMvcResultMatchers.jsonPath("$[0]").value("IntegerScalar")) + .andExpect(MockMvcResultMatchers.jsonPath("$[1]").value("IntegerWaveform")) + .andExpect(MockMvcResultMatchers.jsonPath("$[2]").value("UIntegerScalar")) + .andExpect(MockMvcResultMatchers.jsonPath("$[3]").value("UIntegerWaveform")) + .andExpect(MockMvcResultMatchers.jsonPath("$[4]").doesNotExist()); } @Test @@ -182,23 +185,23 @@ public class DaqRestControllerTest extends AbstractDaqRestTest { .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.jsonPath("$").exists()) - .andExpect(MockMvcResultMatchers.jsonPath("$.minima").exists()) - .andExpect(MockMvcResultMatchers.jsonPath("$.minima.min").exists()) - .andExpect(MockMvcResultMatchers.jsonPath("$.minima.min.value").exists()) - .andExpect(MockMvcResultMatchers.jsonPath("$.minima.min.value").value(100)) - .andExpect(MockMvcResultMatchers.jsonPath("$.minima.min.event").exists()) - .andExpect(MockMvcResultMatchers.jsonPath("$.minima.min.event.channel").exists()) - .andExpect(MockMvcResultMatchers.jsonPath("$.minima.min.event.channel").value(TEST_CHANNEL_NAMES[0])) - .andExpect(MockMvcResultMatchers.jsonPath("$.minima.min.event.pulseId").exists()) - .andExpect(MockMvcResultMatchers.jsonPath("$.minima.min.event.pulseId").value(100)) - .andExpect(MockMvcResultMatchers.jsonPath("$.maxima").exists()) - .andExpect(MockMvcResultMatchers.jsonPath("$.minima.max").exists()) - .andExpect(MockMvcResultMatchers.jsonPath("$.minima.max.value").exists()) - .andExpect(MockMvcResultMatchers.jsonPath("$.minima.max.value").value(101)) - .andExpect(MockMvcResultMatchers.jsonPath("$.minima.max.event").exists()) - .andExpect(MockMvcResultMatchers.jsonPath("$.minima.max.event.channel").exists()) - .andExpect(MockMvcResultMatchers.jsonPath("$.minima.max.event.channel").value(TEST_CHANNEL_NAMES[0])) - .andExpect(MockMvcResultMatchers.jsonPath("$.minima.max.event.pulseId").exists()) - .andExpect(MockMvcResultMatchers.jsonPath("$.minima.max.event.pulseId").value(101)); + .andExpect(MockMvcResultMatchers.jsonPath("$[0].channel").exists()) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].channel").value(TEST_CHANNEL_NAMES[0])) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].data").exists()) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].data.minima").exists()) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].data.minima.min").exists()) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].data.minima.min.value").exists()) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].data.minima.min.value").value(Double.valueOf(100))) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].data.minima.min.event").exists()) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].data.minima.min.event.pulseId").exists()) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].data.minima.min.event.pulseId").value(100)) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].data.maxima").exists()) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].data.maxima.max").exists()) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].data.maxima.max.value").exists()) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].data.maxima.max.value").value(Double.valueOf(101))) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].data.maxima.max.event").exists()) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].data.maxima.max.event.pulseId").exists()) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].data.maxima.max.event.pulseId").value(101)); } + } diff --git a/src/test/java/ch/psi/daq/test/queryrest/query/DummyCassandraReader.java b/src/test/java/ch/psi/daq/test/queryrest/query/DummyCassandraReader.java index a95a2e9..1041abf 100644 --- a/src/test/java/ch/psi/daq/test/queryrest/query/DummyCassandraReader.java +++ b/src/test/java/ch/psi/daq/test/queryrest/query/DummyCassandraReader.java @@ -3,9 +3,9 @@ */ package ch.psi.daq.test.queryrest.query; -import java.awt.image.MultiPixelPackedSampleModel; import java.util.List; import java.util.concurrent.CompletableFuture; +import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -74,7 +74,12 @@ public class DummyCassandraReader implements CassandraReader { */ @Override public Stream getChannelStream(String regex) { - return Stream.of(channels); + Stream channelStream = Stream.of(channels); + if (regex != null) { + Pattern pattern = Pattern.compile(regex.toLowerCase()); + channelStream = Stream.of(channels).filter(channel -> pattern.matcher(channel.toLowerCase()).find()); + } + return channelStream; } /** @@ -132,7 +137,27 @@ public class DummyCassandraReader implements CassandraReader { private Stream getDummyEventStream(String channel, long startIndex, long endIndex) { - return dataGen.generateData(startIndex, (endIndex-startIndex), channel).stream(); + + return dataGen.generateData(startIndex, (endIndex-startIndex + 1), + i -> i, + i -> i, + i -> i, + i -> i, + i -> i, + i -> Long.valueOf(i), + channel).stream(); + } + + private List getDummyEvents(String channel, long startIndex, long endIndex) { + + return dataGen.generateData(startIndex, (endIndex-startIndex + 1), + i -> i, + i -> i, + i -> i, + i -> i, + i -> i, + i -> Long.valueOf(i), + channel); } /** @@ -157,9 +182,9 @@ public class DummyCassandraReader implements CassandraReader { @Override public ChannelEvent getEvent(ChannelEventQueryInfo queryInfo, String... columns) { if (queryInfo.getPulseId() > 0) { - return dataGen.generateData(queryInfo.getPulseId(), 1, queryInfo.getChannel()).get(0); + return (ChannelEvent) getDummyEvents(queryInfo.getChannel(), queryInfo.getPulseId(), queryInfo.getPulseId()).get(0); } - return dataGen.generateData(queryInfo.getGlobalMillis(), 1, queryInfo.getChannel()).get(0); + return (ChannelEvent) getDummyEvents(queryInfo.getChannel(), queryInfo.getGlobalMillis(), queryInfo.getGlobalMillis()).get(0); } /** @@ -175,10 +200,15 @@ public class DummyCassandraReader implements CassandraReader { */ @Override public Stream getChannelEventQueryStream(PulseIdRangeQuery query) { + + return dataGen.generateMetaPulseId( KEYSPACE, query.getStartPulseId(), - (query.getEndPulseId() - query.getStartPulseId()), + (query.getEndPulseId() - query.getStartPulseId() + 1), + i -> i, + i -> i, + i -> i, query.getChannel()).stream(); } @@ -187,15 +217,16 @@ public class DummyCassandraReader implements CassandraReader { */ @Override public Stream getChannelEventQueryStream(TimeRangeQuery query) { + + return dataGen.generateMetaTime( KEYSPACE, query.getStartMillis(), - (query.getEndMillis() - query.getStartMillis()), - query.getChannel()) - .stream() - .map(e -> { - return (ChannelEventQuery) e; - }); + (query.getEndMillis() - query.getStartMillis() + 1), + i -> i, + i -> i, + i -> i, + query.getChannel()).stream(); } /** @@ -203,10 +234,9 @@ public class DummyCassandraReader implements CassandraReader { */ @Override public Stream getMetaPulseIdStream(PulseIdRangeQuery query) { - return dataGen.generateMetaPulseId( - KEYSPACE, - query.getStartPulseId(), (query.getEndPulseId() - query.getStartPulseId()), - query.getChannel()).stream(); + + return getChannelEventQueryStream(query).map(r -> { return (MetaPulseId) r; }); + } @@ -215,10 +245,8 @@ public class DummyCassandraReader implements CassandraReader { */ @Override public Stream getMetaTimeStream(TimeRangeQuery query) { - return dataGen.generateMetaTime( - KEYSPACE, - query.getStartMillis(), (query.getEndMillis() - query.getStartMillis()), - query.getChannel()).stream(); + + return getChannelEventQueryStream(query).map(r -> { return (MetaTime) r; }); } } From 6aa58014912ddde625bf04edb4b7eda265023b27 Mon Sep 17 00:00:00 2001 From: Zellweger Christof Ralf Date: Tue, 27 Oct 2015 18:14:54 +0100 Subject: [PATCH 3/6] ATEST-259: - adding simple CORS filter which includes some standard cors headers --- .../daq/queryrest/config/QueryRestConfig.java | 7 ++++ .../queryrest/filter/SimpleCORSFilter.java | 41 +++++++++++++++++++ src/main/resources/queryrest.properties | 7 +++- 3 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 src/main/java/ch/psi/daq/queryrest/filter/SimpleCORSFilter.java diff --git a/src/main/java/ch/psi/daq/queryrest/config/QueryRestConfig.java b/src/main/java/ch/psi/daq/queryrest/config/QueryRestConfig.java index eebc710..523df3c 100644 --- a/src/main/java/ch/psi/daq/queryrest/config/QueryRestConfig.java +++ b/src/main/java/ch/psi/daq/queryrest/config/QueryRestConfig.java @@ -9,6 +9,7 @@ import java.util.function.Function; import javax.annotation.PostConstruct; import javax.annotation.Resource; +import javax.servlet.Filter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -41,6 +42,7 @@ import ch.psi.daq.query.model.Query; import ch.psi.daq.query.model.QueryField; import ch.psi.daq.query.model.impl.AbstractQuery; import ch.psi.daq.queryrest.controller.validator.QueryValidator; +import ch.psi.daq.queryrest.filter.SimpleCORSFilter; import ch.psi.daq.queryrest.model.PropertyFilterMixin; import ch.psi.daq.queryrest.response.JsonByteArraySerializer; import ch.psi.daq.queryrest.response.JsonStreamSerializer; @@ -178,6 +180,11 @@ public class QueryRestConfig extends WebMvcConfigurerAdapter { public Validator queryValidator() { return new QueryValidator(); } + + @Bean + public Filter simpleCORSFilter() { + return new SimpleCORSFilter(); + } // ========================================================================================== // TODO: This is simply for initial / rudimentary testing - remove once further evolved diff --git a/src/main/java/ch/psi/daq/queryrest/filter/SimpleCORSFilter.java b/src/main/java/ch/psi/daq/queryrest/filter/SimpleCORSFilter.java new file mode 100644 index 0000000..fae4adb --- /dev/null +++ b/src/main/java/ch/psi/daq/queryrest/filter/SimpleCORSFilter.java @@ -0,0 +1,41 @@ +package ch.psi.daq.queryrest.filter; + +import java.io.IOException; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class SimpleCORSFilter implements Filter { + + @Value("${queryrest.enableCORS}") + private boolean enableCORS; + + public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, + ServletException { + + if (enableCORS) { + HttpServletResponse response = (HttpServletResponse) res; + response.setHeader("Access-Control-Allow-Origin", "*"); + response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); + response.setHeader("Access-Control-Max-Age", "3600"); + response.setHeader("Access-Control-Allow-Headers", + "Content-Type, Cache-Control, Accept, Authorization, X-Requested-With"); + } + chain.doFilter(req, res); + } + + public void init(FilterConfig filterConfig) { + } + + public void destroy() { + } +} diff --git a/src/main/resources/queryrest.properties b/src/main/resources/queryrest.properties index 55b2cd3..0915ca8 100644 --- a/src/main/resources/queryrest.properties +++ b/src/main/resources/queryrest.properties @@ -1,4 +1,9 @@ # defines the fields that are included in the response # if no fields have been specified by the user queryrest.default.response.fields=channel,pulseId,globalMillis,globalNanos,iocMillis,iocNanos,shape,value -queryrest.default.response.aggregations=min,max,sum \ No newline at end of file + +# aggregation which are included in the response by default if aggregation is enabled for a given query +queryrest.default.response.aggregations=min,max,sum + +# enables / disables the CORS servlet filter. Adds multiple CORS headers to the response +queryrest.enableCORS=true \ No newline at end of file From cd72af733a9441fe1f959d8e333ad1cbebb41f4c Mon Sep 17 00:00:00 2001 From: Zellweger Christof Ralf Date: Wed, 28 Oct 2015 12:52:32 +0100 Subject: [PATCH 4/6] ATEST-259: - adding tests, re-implementing a simpler CORS filter than previously used --- .project | 6 - .settings/org.eclipse.jdt.core.prefs | 2 +- build.gradle | 3 + .../daq/queryrest/config/QueryRestConfig.java | 23 +-- .../psi/daq/queryrest/filter/CorsFilter.java | 80 ++++++++++ .../queryrest/filter/SimpleCORSFilter.java | 41 ------ src/main/resources/queryrest.properties | 10 +- .../test/queryrest/AbstractDaqRestTest.java | 6 +- ...Test.java => QueryRestControllerTest.java} | 138 +++++++++++++++--- 9 files changed, 225 insertions(+), 84 deletions(-) create mode 100644 src/main/java/ch/psi/daq/queryrest/filter/CorsFilter.java delete mode 100644 src/main/java/ch/psi/daq/queryrest/filter/SimpleCORSFilter.java rename src/test/java/ch/psi/daq/test/queryrest/controller/{DaqRestControllerTest.java => QueryRestControllerTest.java} (66%) diff --git a/.project b/.project index 08328ec..56f8001 100644 --- a/.project +++ b/.project @@ -5,11 +5,6 @@ - - org.eclipse.wst.common.project.facet.core.builder - - - org.eclipse.jdt.core.javabuilder @@ -25,6 +20,5 @@ org.springframework.ide.eclipse.core.springnature org.springsource.ide.eclipse.gradle.core.nature org.eclipse.jdt.core.javanature - org.eclipse.wst.common.project.facet.core.nature diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs index 38cfd99..e174e59 100644 --- a/.settings/org.eclipse.jdt.core.prefs +++ b/.settings/org.eclipse.jdt.core.prefs @@ -1,5 +1,5 @@ # -#Wed Sep 16 07:23:26 CEST 2015 +#Wed Oct 28 07:37:57 CET 2015 org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.compliance=1.8 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve diff --git a/build.gradle b/build.gradle index bc33bf7..223bf31 100644 --- a/build.gradle +++ b/build.gradle @@ -30,6 +30,9 @@ dependencies { testCompile libraries.spring_boot_starter_test testCompile libraries.jsonassert testCompile libraries.jsonpath + + testCompile 'com.jayway.restassured:rest-assured:2.4.1' + testCompile 'com.jayway.restassured:spring-mock-mvc:2.4.1' } uploadArchives { diff --git a/src/main/java/ch/psi/daq/queryrest/config/QueryRestConfig.java b/src/main/java/ch/psi/daq/queryrest/config/QueryRestConfig.java index 523df3c..3dc83c4 100644 --- a/src/main/java/ch/psi/daq/queryrest/config/QueryRestConfig.java +++ b/src/main/java/ch/psi/daq/queryrest/config/QueryRestConfig.java @@ -24,12 +24,6 @@ import org.springframework.util.StringUtils; import org.springframework.validation.Validator; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; -import com.fasterxml.jackson.annotation.JsonInclude.Include; -import com.fasterxml.jackson.core.JsonFactory; -import com.fasterxml.jackson.core.Version; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.module.SimpleModule; - import ch.psi.daq.cassandra.util.test.CassandraDataGen; import ch.psi.daq.common.json.deserialize.AttributeBasedDeserializer; import ch.psi.daq.common.statistic.StorelessStatistics; @@ -42,12 +36,18 @@ import ch.psi.daq.query.model.Query; import ch.psi.daq.query.model.QueryField; import ch.psi.daq.query.model.impl.AbstractQuery; import ch.psi.daq.queryrest.controller.validator.QueryValidator; -import ch.psi.daq.queryrest.filter.SimpleCORSFilter; +import ch.psi.daq.queryrest.filter.CorsFilter; import ch.psi.daq.queryrest.model.PropertyFilterMixin; import ch.psi.daq.queryrest.response.JsonByteArraySerializer; import ch.psi.daq.queryrest.response.JsonStreamSerializer; import ch.psi.daq.queryrest.response.ResponseStreamWriter; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.Version; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; + @Configuration @PropertySource(value = {"classpath:queryrest.properties"}) @PropertySource(value = {"file:${user.home}/.config/daq/queryrest.properties"}, ignoreResourceNotFound = true) @@ -180,10 +180,15 @@ public class QueryRestConfig extends WebMvcConfigurerAdapter { public Validator queryValidator() { return new QueryValidator(); } + +// @Bean +// public Filter regexCORSFilter() { +// return new RegexCORSFilter(); +// } @Bean - public Filter simpleCORSFilter() { - return new SimpleCORSFilter(); + public Filter corsFilter() { + return new CorsFilter(); } // ========================================================================================== diff --git a/src/main/java/ch/psi/daq/queryrest/filter/CorsFilter.java b/src/main/java/ch/psi/daq/queryrest/filter/CorsFilter.java new file mode 100644 index 0000000..31c24a5 --- /dev/null +++ b/src/main/java/ch/psi/daq/queryrest/filter/CorsFilter.java @@ -0,0 +1,80 @@ +package ch.psi.daq.queryrest.filter; + +import java.io.IOException; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.filter.OncePerRequestFilter; + +public class CorsFilter extends OncePerRequestFilter { + + private static final String ALLOW_ORIGIN_HEADER = "Access-Control-Allow-Origin"; + + @Value("${queryrest.cors.allowedorigins}") + private String configuredOrigins; + + @Value("${queryrest.cors.forceallheaders}") + private boolean forceAllHeaders; + + + + /** + * @{inheritDoc + */ + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + + Set allowedOrigins = new HashSet(Arrays.asList(configuredOrigins.split(",")) + .stream() + .map(s -> { + return s.trim(); }) + .collect(Collectors.toList())); + + String originHeader = request.getHeader("Origin"); + if (forceAllHeaders) { + // include headers no matter what - good for development + if (allowedOrigins.contains(originHeader)) { + response.addHeader(ALLOW_ORIGIN_HEADER, originHeader); + } else { + response.addHeader(ALLOW_ORIGIN_HEADER, "*"); + } + setDefaultCorsHeaders(response); + + } else if (request.getHeader("Access-Control-Request-Method") != null && "OPTIONS".equals(request.getMethod())) { + // this is for 'real' Cross-site browser requests + if (allowedOrigins.contains(originHeader)) { + response.addHeader(ALLOW_ORIGIN_HEADER, originHeader); + } + setDefaultCorsHeaders(response); + } + + filterChain.doFilter(request, response); + } + + + private void setDefaultCorsHeaders(HttpServletResponse response) { + response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); + response.addHeader("Access-Control-Allow-Headers", "Origin, Authorization, Accept, Content-Type"); + response.addHeader("Access-Control-Max-Age", "1800"); + } + + + public void setConfiguredOrigins(String configuredOrigins) { + this.configuredOrigins = configuredOrigins; + } + + + public void setForceAllHeaders(boolean forceAllHeaders) { + this.forceAllHeaders = forceAllHeaders; + } + +} diff --git a/src/main/java/ch/psi/daq/queryrest/filter/SimpleCORSFilter.java b/src/main/java/ch/psi/daq/queryrest/filter/SimpleCORSFilter.java deleted file mode 100644 index fae4adb..0000000 --- a/src/main/java/ch/psi/daq/queryrest/filter/SimpleCORSFilter.java +++ /dev/null @@ -1,41 +0,0 @@ -package ch.psi.daq.queryrest.filter; - -import java.io.IOException; - -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletResponse; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -@Component -public class SimpleCORSFilter implements Filter { - - @Value("${queryrest.enableCORS}") - private boolean enableCORS; - - public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, - ServletException { - - if (enableCORS) { - HttpServletResponse response = (HttpServletResponse) res; - response.setHeader("Access-Control-Allow-Origin", "*"); - response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); - response.setHeader("Access-Control-Max-Age", "3600"); - response.setHeader("Access-Control-Allow-Headers", - "Content-Type, Cache-Control, Accept, Authorization, X-Requested-With"); - } - chain.doFilter(req, res); - } - - public void init(FilterConfig filterConfig) { - } - - public void destroy() { - } -} diff --git a/src/main/resources/queryrest.properties b/src/main/resources/queryrest.properties index 0915ca8..4acde24 100644 --- a/src/main/resources/queryrest.properties +++ b/src/main/resources/queryrest.properties @@ -6,4 +6,12 @@ queryrest.default.response.fields=channel,pulseId,globalMillis,globalNanos,iocMi queryrest.default.response.aggregations=min,max,sum # enables / disables the CORS servlet filter. Adds multiple CORS headers to the response -queryrest.enableCORS=true \ No newline at end of file +queryrest.enableCORS=true + +# includes the CORS headers no matter what request or preflight was sent. If an Origin header is set, this header will be used. +# If no Origin header is set, '*' will be used. +queryrest.cors.forceallheaders=true + +# defines a specific regex to be used in the Access-Control-Allow-Origin. This property needs to be specified +# but might be null or the empty string (""), i.e. don't comment it out. +queryrest.cors.allowedorigins=http://localhost:8080, * \ No newline at end of file diff --git a/src/test/java/ch/psi/daq/test/queryrest/AbstractDaqRestTest.java b/src/test/java/ch/psi/daq/test/queryrest/AbstractDaqRestTest.java index bf3ae66..fd725a4 100644 --- a/src/test/java/ch/psi/daq/test/queryrest/AbstractDaqRestTest.java +++ b/src/test/java/ch/psi/daq/test/queryrest/AbstractDaqRestTest.java @@ -27,9 +27,9 @@ import ch.psi.daq.test.cassandra.CassandraDaqUnitDependencyInjectionTestExecutio CassandraDaqUnitDependencyInjectionTestExecutionListener.class, DependencyInjectionTestExecutionListener.class}) @SpringApplicationConfiguration(classes = { - QueryRestApplication.class - ,QueryRestConfig.class - ,DaqWebMvcConfig.class + QueryRestApplication.class, + QueryRestConfig.class, + DaqWebMvcConfig.class }) @DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD) @WebAppConfiguration diff --git a/src/test/java/ch/psi/daq/test/queryrest/controller/DaqRestControllerTest.java b/src/test/java/ch/psi/daq/test/queryrest/controller/QueryRestControllerTest.java similarity index 66% rename from src/test/java/ch/psi/daq/test/queryrest/controller/DaqRestControllerTest.java rename to src/test/java/ch/psi/daq/test/queryrest/controller/QueryRestControllerTest.java index 6745580..03c91d5 100644 --- a/src/test/java/ch/psi/daq/test/queryrest/controller/DaqRestControllerTest.java +++ b/src/test/java/ch/psi/daq/test/queryrest/controller/QueryRestControllerTest.java @@ -8,6 +8,7 @@ import org.springframework.http.MediaType; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.result.MockMvcResultHandlers; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; import ch.psi.daq.cassandra.util.test.CassandraDataGen; import ch.psi.daq.common.ordering.Ordering; @@ -16,30 +17,34 @@ import ch.psi.daq.query.model.impl.PulseRangeQuery; import ch.psi.daq.query.model.impl.TimeRangeQuery; import ch.psi.daq.query.model.impl.TimeRangeQueryDate; import ch.psi.daq.queryrest.controller.QueryRestController; +import ch.psi.daq.queryrest.filter.CorsFilter; import ch.psi.daq.test.cassandra.admin.CassandraTestAdmin; import ch.psi.daq.test.queryrest.AbstractDaqRestTest; /** * Tests the {@link DaqController} implementation. */ -public class DaqRestControllerTest extends AbstractDaqRestTest { - +public class QueryRestControllerTest extends AbstractDaqRestTest { + @Resource private CassandraTestAdmin cassandraTestAdmin; @Resource private CassandraDataGen dataGen; - - public static final String[] TEST_CHANNEL_NAMES = new String[]{"testChannel1", "testChannel2"}; - + + @Resource + private CorsFilter corsFilter; + + public static final String[] TEST_CHANNEL_NAMES = new String[] {"testChannel1", "testChannel2"}; + @After public void tearDown() throws Exception {} @Test public void testChannelNameQuery() throws Exception { - + this.mockMvc.perform( - MockMvcRequestBuilders + MockMvcRequestBuilders .get(QueryRestController.CHANNELS) .contentType(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultHandlers.print()) @@ -48,15 +53,15 @@ public class DaqRestControllerTest extends AbstractDaqRestTest { .andExpect(MockMvcResultMatchers.jsonPath("$[0]").exists()) .andExpect(MockMvcResultMatchers.jsonPath("$[0]").value("BooleanScalar")) .andExpect(MockMvcResultMatchers.jsonPath("$[1]").value("BooleanWaveform")); - + } - + @Test public void testSpecificChannelSearch() throws Exception { this.mockMvc.perform( MockMvcRequestBuilders - .get(QueryRestController.CHANNELS + "/integer") - .contentType(MediaType.APPLICATION_JSON)) + .get(QueryRestController.CHANNELS + "/integer") + .contentType(MediaType.APPLICATION_JSON)) .andDo(MockMvcResultHandlers.print()) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.jsonPath("$").isArray()) @@ -67,7 +72,93 @@ public class DaqRestControllerTest extends AbstractDaqRestTest { .andExpect(MockMvcResultMatchers.jsonPath("$[3]").value("UIntegerWaveform")) .andExpect(MockMvcResultMatchers.jsonPath("$[4]").doesNotExist()); } - + + @Test + public void testCorsFilterNoHeaders() throws Exception { + corsFilter.setForceAllHeaders(false); + this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).addFilters(corsFilter).build(); + + this.mockMvc.perform( + MockMvcRequestBuilders + .options(QueryRestController.CHANNELS) + .contentType(MediaType.APPLICATION_JSON)) + .andDo(MockMvcResultHandlers.print()) + .andExpect(MockMvcResultMatchers.status().isOk()) + // we didn't set the 'Origin' header so no access-control + .andExpect(MockMvcResultMatchers.header().doesNotExist("Access-Control-Allow-Origin")); + } + + @Test + public void testCorsFilterIncludesHeaders() throws Exception { + // all headers are set + this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).addFilters(corsFilter).build(); + + this.mockMvc.perform( + MockMvcRequestBuilders + .options(QueryRestController.CHANNELS) + .header("Origin", "*") + .contentType(MediaType.APPLICATION_JSON)) + .andDo(MockMvcResultHandlers.print()) + .andExpect(MockMvcResultMatchers.status().isOk()) + // we didn't set the 'Origin' header so no access-control + .andExpect(MockMvcResultMatchers.header().string("Access-Control-Allow-Origin", "*")); + + this.mockMvc.perform( + MockMvcRequestBuilders + .options(QueryRestController.CHANNELS) + .header("Origin", "http://localhost:8080") + .contentType(MediaType.APPLICATION_JSON)) + .andDo(MockMvcResultHandlers.print()) + .andExpect(MockMvcResultMatchers.status().isOk()) + // we didn't set the 'Origin' header so no access-control + .andExpect(MockMvcResultMatchers.header().string("Access-Control-Allow-Origin", "http://localhost:8080")); + + this.mockMvc.perform( + MockMvcRequestBuilders + .options(QueryRestController.CHANNELS) + .header("Origin", "someBogusDomain.com") + .contentType(MediaType.APPLICATION_JSON)) + .andDo(MockMvcResultHandlers.print()) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.header().string("Access-Control-Allow-Origin", "*")); + + } + + @Test + public void testCorsFilterMismatchSpecificOrigin() throws Exception { + corsFilter.setForceAllHeaders(false); + this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).addFilters(corsFilter).build(); + + this.mockMvc + .perform( + MockMvcRequestBuilders + .options(QueryRestController.CHANNELS) + .header("Origin", "*") + .header("Access-Control-Request-Method", "GET") + .contentType(MediaType.APPLICATION_JSON)) + .andDo(MockMvcResultHandlers.print()) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.header().string("Access-Control-Allow-Origin", "*")) + .andExpect( + MockMvcResultMatchers.header().string("Access-Control-Allow-Headers", + "Origin, Authorization, Accept, Content-Type")); + + this.mockMvc + .perform( + MockMvcRequestBuilders + .options(QueryRestController.CHANNELS) + .header("Origin", "someBogusDomain.com") + .header("Access-Control-Request-Method", "GET") + .contentType(MediaType.APPLICATION_JSON)) + .andDo(MockMvcResultHandlers.print()) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.header().doesNotExist("Access-Control-Allow-Origin")) + .andExpect( + MockMvcResultMatchers.header().string("Access-Control-Allow-Headers", + "Origin, Authorization, Accept, Content-Type")); + } + + @Test public void testPulseRangeQuery() throws Exception { PulseRangeQuery request = new PulseRangeQuery( @@ -77,9 +168,9 @@ public class DaqRestControllerTest extends AbstractDaqRestTest { String content = mapper.writeValueAsString(request); System.out.println(content); - + content = "{\"channels\":[\"testChannel1\",\"testChannel2\"],\"startPulseId\":100,\"endPulseId\":101}"; - + this.mockMvc .perform(MockMvcRequestBuilders .post(QueryRestController.QUERY) @@ -111,9 +202,9 @@ public class DaqRestControllerTest extends AbstractDaqRestTest { String content = mapper.writeValueAsString(request); this.mockMvc.perform(MockMvcRequestBuilders - .post(QueryRestController.QUERY) - .contentType(MediaType.APPLICATION_JSON) - .content(content)) + .post(QueryRestController.QUERY) + .contentType(MediaType.APPLICATION_JSON) + .content(content)) .andDo(MockMvcResultHandlers.print()) .andExpect(MockMvcResultMatchers.status().isOk()) @@ -145,9 +236,9 @@ public class DaqRestControllerTest extends AbstractDaqRestTest { this.mockMvc .perform( MockMvcRequestBuilders - .post(QueryRestController.QUERY) - .contentType(MediaType.APPLICATION_JSON) - .content(content) + .post(QueryRestController.QUERY) + .contentType(MediaType.APPLICATION_JSON) + .content(content) ) .andDo(MockMvcResultHandlers.print()) .andExpect(MockMvcResultMatchers.status().isOk()) @@ -163,7 +254,7 @@ public class DaqRestControllerTest extends AbstractDaqRestTest { .andExpect(MockMvcResultMatchers.jsonPath("$[1].data[0].pulseId").value(100)) .andExpect(MockMvcResultMatchers.jsonPath("$[1].data[1].pulseId").value(101)); } - + @Test public void testExtremaAggregation() throws Exception { PulseRangeQuery request = new PulseRangeQuery( @@ -183,7 +274,7 @@ public class DaqRestControllerTest extends AbstractDaqRestTest { .andDo(MockMvcResultHandlers.print()) .andExpect(MockMvcResultMatchers.status().isOk()) - + .andExpect(MockMvcResultMatchers.jsonPath("$").exists()) .andExpect(MockMvcResultMatchers.jsonPath("$[0].channel").exists()) .andExpect(MockMvcResultMatchers.jsonPath("$[0].channel").value(TEST_CHANNEL_NAMES[0])) @@ -203,5 +294,6 @@ public class DaqRestControllerTest extends AbstractDaqRestTest { .andExpect(MockMvcResultMatchers.jsonPath("$[0].data.maxima.max.event.pulseId").exists()) .andExpect(MockMvcResultMatchers.jsonPath("$[0].data.maxima.max.event.pulseId").value(101)); } - + + } From e7467aeea1689352a8ae147247594ea2dcf294f9 Mon Sep 17 00:00:00 2001 From: Zellweger Christof Ralf Date: Wed, 28 Oct 2015 12:53:32 +0100 Subject: [PATCH 5/6] ATEST-259: - removing unused test dependencies --- .settings/org.eclipse.jdt.core.prefs | 2 +- build.gradle | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs index e174e59..5b5155d 100644 --- a/.settings/org.eclipse.jdt.core.prefs +++ b/.settings/org.eclipse.jdt.core.prefs @@ -1,5 +1,5 @@ # -#Wed Oct 28 07:37:57 CET 2015 +#Wed Oct 28 12:53:12 CET 2015 org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.compliance=1.8 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve diff --git a/build.gradle b/build.gradle index 223bf31..bc33bf7 100644 --- a/build.gradle +++ b/build.gradle @@ -30,9 +30,6 @@ dependencies { testCompile libraries.spring_boot_starter_test testCompile libraries.jsonassert testCompile libraries.jsonpath - - testCompile 'com.jayway.restassured:rest-assured:2.4.1' - testCompile 'com.jayway.restassured:spring-mock-mvc:2.4.1' } uploadArchives { From 00e181c8aa5b7e75a3421872219f28f71901b56f Mon Sep 17 00:00:00 2001 From: Zellweger Christof Ralf Date: Wed, 28 Oct 2015 13:03:18 +0100 Subject: [PATCH 6/6] ATEST-259: - clean up, improving naming --- .../java/ch/psi/daq/queryrest/config/QueryRestConfig.java | 7 ++----- src/main/resources/queryrest.properties | 7 ++----- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/main/java/ch/psi/daq/queryrest/config/QueryRestConfig.java b/src/main/java/ch/psi/daq/queryrest/config/QueryRestConfig.java index 3dc83c4..78eaf75 100644 --- a/src/main/java/ch/psi/daq/queryrest/config/QueryRestConfig.java +++ b/src/main/java/ch/psi/daq/queryrest/config/QueryRestConfig.java @@ -13,6 +13,7 @@ import javax.servlet.Filter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @@ -181,12 +182,8 @@ public class QueryRestConfig extends WebMvcConfigurerAdapter { return new QueryValidator(); } -// @Bean -// public Filter regexCORSFilter() { -// return new RegexCORSFilter(); -// } - @Bean + @ConditionalOnProperty("queryrest.cors.enable") public Filter corsFilter() { return new CorsFilter(); } diff --git a/src/main/resources/queryrest.properties b/src/main/resources/queryrest.properties index 4acde24..9ee6bf6 100644 --- a/src/main/resources/queryrest.properties +++ b/src/main/resources/queryrest.properties @@ -6,12 +6,9 @@ queryrest.default.response.fields=channel,pulseId,globalMillis,globalNanos,iocMi queryrest.default.response.aggregations=min,max,sum # enables / disables the CORS servlet filter. Adds multiple CORS headers to the response -queryrest.enableCORS=true - +queryrest.cors.enable=true # includes the CORS headers no matter what request or preflight was sent. If an Origin header is set, this header will be used. # If no Origin header is set, '*' will be used. queryrest.cors.forceallheaders=true - -# defines a specific regex to be used in the Access-Control-Allow-Origin. This property needs to be specified -# but might be null or the empty string (""), i.e. don't comment it out. +# defines the allowed origins for CORS requests. Only relevant if queryrest.enableCORS==true (see above). queryrest.cors.allowedorigins=http://localhost:8080, * \ No newline at end of file