/*
* Copyright 2013-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.xd.dirt.stream;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import static org.springframework.xd.dirt.stream.ParsingContext.*;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.annotation.Bean;
import org.springframework.xd.dirt.module.ModuleRegistry;
import org.springframework.xd.dirt.stream.dsl.StreamDefinitionException;
import org.springframework.xd.dirt.zookeeper.EmbeddedZooKeeper;
import org.springframework.xd.dirt.zookeeper.ZooKeeperConnection;
import org.springframework.xd.module.ModuleDescriptor;
import org.springframework.xd.module.ModuleType;
import org.springframework.xd.module.TestModuleDefinitions;
import org.springframework.xd.module.options.DefaultModuleOptionsMetadataResolver;
/**
* @author Mark Fisher
* @author David Turanski
*/
public class XDStreamParserTests {
private XDStreamParser parser;
@Before
public void setup() {
parser = new XDStreamParser(moduleRegistry(), new DefaultModuleOptionsMetadataResolver());
}
@Test
public void testJob() {
List<ModuleDescriptor> requests = parser.parse("myJob", "job", job);
assertEquals(1, requests.size());
ModuleDescriptor job = requests.get(0);
assertEquals("job", job.getModuleName());
assertEquals("myJob", job.getGroup());
assertEquals(0, job.getIndex());
assertEquals(ModuleType.job, job.getType());
assertEquals(0, job.getParameters().size());
}
@Test
public void testJobWithParams() {
List<ModuleDescriptor> requests = parser.parse("myJob", "job --foo=bar", job);
assertEquals(1, requests.size());
ModuleDescriptor job = requests.get(0);
assertEquals("job", job.getModuleName());
assertEquals("myJob", job.getGroup());
assertEquals(0, job.getIndex());
assertEquals(ModuleType.job, job.getType());
assertEquals(1, job.getParameters().size());
assertEquals("bar", job.getParameters().get("foo"));
}
@Test
public void simpleStream() {
List<ModuleDescriptor> requests = parser.parse("test", "foo | bar", stream);
assertEquals(2, requests.size());
ModuleDescriptor sink = requests.get(0);
ModuleDescriptor source = requests.get(1);
assertEquals("foo", source.getModuleName());
assertEquals("test", source.getGroup());
assertEquals(0, source.getIndex());
assertEquals(ModuleType.source, source.getType());
assertEquals(0, source.getParameters().size());
assertEquals("bar", sink.getModuleName());
assertEquals("test", sink.getGroup());
assertEquals(1, sink.getIndex());
assertEquals(ModuleType.sink, sink.getType());
assertEquals(0, sink.getParameters().size());
}
@Test
public void quotesInParams() {
List<ModuleDescriptor> requests = parser.parse("test", "foo --bar='payload.matches(''hello'')' | file",
stream);
assertEquals(2, requests.size());
// ModuleDescriptor sink = requests.get(0);
ModuleDescriptor source = requests.get(1);
assertEquals("foo", source.getModuleName());
assertEquals("test", source.getGroup());
assertEquals(0, source.getIndex());
assertEquals(ModuleType.source, source.getType());
Map<String, String> sourceParameters = source.getParameters();
assertEquals(1, sourceParameters.size());
assertEquals("payload.matches('hello')", sourceParameters.get("bar"));
}
@Test
public void quotesInParams2() {
List<ModuleDescriptor> requests = parser.parse("test",
"http --port=9700 | filter --expression=payload.matches('hello world') | file", stream);
assertEquals(3, requests.size());
ModuleDescriptor filter = requests.get(1);
assertEquals("filter", filter.getModuleName());
assertEquals("test", filter.getGroup());
assertEquals(1, filter.getIndex());
assertEquals(ModuleType.processor, filter.getType());
Map<String, String> sourceParameters = filter.getParameters();
assertEquals(1, sourceParameters.size());
assertEquals("payload.matches('hello world')", sourceParameters.get("expression"));
}
@Test
public void parameterizedModules() {
List<ModuleDescriptor> requests = parser.parse("test", "foo --x=1 --y=two | bar --z=3", stream);
assertEquals(2, requests.size());
ModuleDescriptor sink = requests.get(0);
ModuleDescriptor source = requests.get(1);
assertEquals("foo", source.getModuleName());
assertEquals("test", source.getGroup());
assertEquals(0, source.getIndex());
assertEquals(ModuleType.source, source.getType());
Map<String, String> sourceParameters = source.getParameters();
assertEquals(2, sourceParameters.size());
assertEquals("1", sourceParameters.get("x"));
assertEquals("two", sourceParameters.get("y"));
assertEquals("bar", sink.getModuleName());
assertEquals("test", sink.getGroup());
assertEquals(1, sink.getIndex());
assertEquals(ModuleType.sink, sink.getType());
Map<String, String> sinkParameters = sink.getParameters();
assertEquals(1, sinkParameters.size());
assertEquals("3", sinkParameters.get("z"));
}
@Test
public void sourceChannelNameIsAppliedToSourceModule() throws Exception {
List<ModuleDescriptor> requests = parser.parse("test", "topic:foo > goo | blah | file", stream);
assertEquals(3, requests.size());
assertEquals("topic:foo", requests.get(2).getSourceChannelName());
assertEquals(ModuleType.processor, requests.get(2).getType());
assertEquals(ModuleType.processor, requests.get(1).getType());
assertEquals(ModuleType.sink, requests.get(0).getType());
}
@Test
public void sinkChannelNameIsAppliedToSinkModule() throws Exception {
List<ModuleDescriptor> requests = parser.parse("test", "boo | blah | aaak > queue:foo", stream);
assertEquals(3, requests.size());
assertEquals("queue:foo", requests.get(0).getSinkChannelName());
assertEquals(ModuleType.processor, requests.get(0).getType());
assertEquals(ModuleType.processor, requests.get(1).getType());
assertEquals(ModuleType.source, requests.get(2).getType());
}
@Test
public void tap() throws Exception {
StreamDefinitionRepository streamRepo = mock(StreamDefinitionRepository.class);
parser = new XDStreamParser(streamRepo, moduleRegistry(),
new DefaultModuleOptionsMetadataResolver());
when(streamRepo.findOne("xxx")).thenReturn(new StreamDefinition("xxx", "http | file"));
List<ModuleDescriptor> requests = parser.parse("test", "tap:stream:xxx.http > file", stream);
assertEquals(1, requests.size());
assertEquals("tap:stream:xxx.http.0", requests.get(0).getSourceChannelName());
assertEquals(ModuleType.sink, requests.get(0).getType());
}
@Test
public void simpleSinkNamedChannel() throws Exception {
List<ModuleDescriptor> requests = parser.parse("test", "bart > queue:foo", stream);
assertEquals(1, requests.size());
assertEquals("queue:foo", requests.get(0).getSinkChannelName());
assertEquals(ModuleType.source, requests.get(0).getType());
}
@Test
public void simpleSinkNamedChannelBadType() throws Exception {
// The parser will identify this as a Named channel sink and thus badLog will be
// labeled a source.
// But badLog is a sink and there should be an exception thrown by the parser.
boolean isException = false;
try {
parser.parse("test", "badLog > :foo", stream);
}
catch (Exception e) {
isException = true;
}
assertTrue(isException);
}
@Test
public void simpleSourceNamedChannel() throws Exception {
List<ModuleDescriptor> requests = parser.parse("test", "queue:foo > boot", stream);
assertEquals(1, requests.size());
assertEquals("queue:foo", requests.get(0).getSourceChannelName());
assertEquals(ModuleType.sink, requests.get(0).getType());
}
@Test
public void namedChannelsForbiddenInComposedModules() {
try {
parser.parse("test", "queue:foo > boot", module);
}
catch (StreamDefinitionException expected) {
assertThat(expected.getMessage(),
containsString("A named channel is not supported in this kind of definition"));
assertThat(expected.getPosition(), is(0));
}
try {
parser.parse("test", "bart | goo > queue:foo", module);
}
catch (StreamDefinitionException expected) {
assertThat(expected.getMessage(),
containsString("A named channel is not supported in this kind of definition"));
assertThat(expected.getPosition(), is(13));
}
}
@Bean
public ZooKeeperConnection zooKeeperConnection() {
return new ZooKeeperConnection("localhost:" + embeddedZooKeeper().getClientPort());
}
@Bean
public EmbeddedZooKeeper embeddedZooKeeper() {
return new EmbeddedZooKeeper();
}
@Bean
public ModuleRegistry moduleRegistry() {
ModuleRegistry registry = mock(ModuleRegistry.class);
setupMockFindsForSource(registry);
setupMockFindsForSink(registry);
setupMockFindsForProcessor(registry);
setupMockFindsForJobs(registry);
when(registry.findDefinition("bart", ModuleType.source)).thenReturn(TestModuleDefinitions.dummy("bart",
ModuleType.source));
when(registry.findDefinition("foo", ModuleType.source)).thenReturn(TestModuleDefinitions.dummy("foo",
ModuleType.source));
when(registry.findDefinition("boo", ModuleType.source)).thenReturn(TestModuleDefinitions.dummy("boo",
ModuleType.source));
when(registry.findDefinition("http", ModuleType.source)).thenReturn(TestModuleDefinitions.dummy("http",
ModuleType.source));
when(registry.findDefinition("boot", ModuleType.sink)).thenReturn(TestModuleDefinitions.dummy("boot",
ModuleType.sink));
when(registry.findDefinition("bar", ModuleType.sink)).thenReturn(TestModuleDefinitions.dummy("bar",
ModuleType.sink));
when(registry.findDefinition("badLog", ModuleType.sink)).thenReturn(TestModuleDefinitions.dummy("badLog",
ModuleType.sink));
when(registry.findDefinition("file", ModuleType.sink)).thenReturn(TestModuleDefinitions.dummy("file",
ModuleType.sink));
when(registry.findDefinition("job", ModuleType.job)).thenReturn(TestModuleDefinitions.dummy("job",
ModuleType.job));
when(registry.findDefinition("aaak", ModuleType.processor)).thenReturn(TestModuleDefinitions.dummy("aaak",
ModuleType.processor));
when(registry.findDefinition("goo", ModuleType.processor)).thenReturn(TestModuleDefinitions.dummy("goo",
ModuleType.processor));
when(registry.findDefinition("blah", ModuleType.processor)).thenReturn(TestModuleDefinitions.dummy("blah",
ModuleType.processor));
when(registry.findDefinition("filter", ModuleType.processor)).thenReturn(TestModuleDefinitions.dummy("filter",
ModuleType.processor));
return registry;
}
private void setupMockFindsForSource(ModuleRegistry registry) {
when(registry.findDefinitions("source")).thenReturn(Collections.singletonList(TestModuleDefinitions.dummy("source",
ModuleType.source)));
when(registry.findDefinitions("foo")).thenReturn(Collections.singletonList(TestModuleDefinitions.dummy("foo",
ModuleType.source)));
when(registry.findDefinitions("boo")).thenReturn(Collections.singletonList(TestModuleDefinitions.dummy("boo",
ModuleType.source)));
when(registry.findDefinitions("http")).thenReturn(Collections.singletonList(TestModuleDefinitions.dummy("http",
ModuleType.source)));
}
private void setupMockFindsForSink(ModuleRegistry registry) {
when(registry.findDefinitions("sink")).thenReturn(Collections.singletonList(TestModuleDefinitions.dummy("sink",
ModuleType.sink)));
when(registry.findDefinitions("file")).thenReturn(Collections.singletonList(TestModuleDefinitions.dummy("file",
ModuleType.sink)));
when(registry.findDefinitions("boot")).thenReturn(Collections.singletonList(TestModuleDefinitions.dummy("boot",
ModuleType.sink)));
when(registry.findDefinitions("bar")).thenReturn(Collections.singletonList(TestModuleDefinitions.dummy("bar",
ModuleType.sink)));
}
private void setupMockFindsForProcessor(ModuleRegistry registry) {
when(registry.findDefinitions("processor")).thenReturn(
Collections.singletonList(TestModuleDefinitions.dummy("processor",
ModuleType.processor)));
when(registry.findDefinitions("blah")).thenReturn(Collections.singletonList(TestModuleDefinitions.dummy("blah",
ModuleType.processor)));
when(registry.findDefinitions("filter")).thenReturn(Collections.singletonList(TestModuleDefinitions.dummy("filter",
ModuleType.processor)));
when(registry.findDefinitions("goo")).thenReturn(Collections.singletonList(TestModuleDefinitions.dummy("goo",
ModuleType.processor)));
when(registry.findDefinitions("aaak")).thenReturn(Collections.singletonList(TestModuleDefinitions.dummy("aaak",
ModuleType.processor)));
}
private void setupMockFindsForJobs(ModuleRegistry registry) {
when(registry.findDefinitions("job")).thenReturn(Collections.singletonList(TestModuleDefinitions.dummy("job",
ModuleType.job)));
}
}