/*
* Copyright (c) 2002-2012 Alibaba Group Holding Limited.
* All rights reserved.
*
* 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 com.alibaba.citrus.service.pipeline;
import static com.alibaba.citrus.test.TestUtil.*;
import static org.junit.Assert.*;
import com.alibaba.citrus.service.pipeline.impl.PipelineImpl;
import com.alibaba.citrus.service.pipeline.valve.LogAndBreakValve;
import com.alibaba.citrus.service.pipeline.valve.LogAndInvokeSubValve;
import com.alibaba.citrus.service.pipeline.valve.LogAndReturnValve;
import com.alibaba.citrus.service.pipeline.valve.LogValve;
import org.junit.Before;
import org.junit.Test;
/**
* 测试pipeline本身的功能,不包括配置。
*
* @author Michael Zhou
*/
public class PipelineTests extends AbstractPipelineTests {
@Before
public void init() {
pipeline = createPipeline();
}
@Test
public void pipeline_getLabel() throws Exception {
// init is null
assertNull(pipeline.getLabel());
// set empty label
pipeline.setLabel(null);
assertNull(pipeline.getLabel());
pipeline.setLabel(" ");
assertNull(pipeline.getLabel());
// set value
pipeline.setLabel(" testLabel");
assertEquals("testLabel", pipeline.getLabel());
}
@Test
public void pipeline_getValves() throws Exception {
// init value
assertArrayEquals(new Valve[0], pipeline.getValves());
// set null
pipeline = createPipeline((Valve[]) null);
assertArrayEquals(new Valve[0], pipeline.getValves());
}
@Test
public void pipeline_newInvocation() throws Exception {
pipeline = createPipeline(new LogValve(), new LogValve(), new LogValve());
try {
pipeline.newInvocation(null);
fail();
} catch (IllegalArgumentException e) {
assertThat(e, exception("no parent PipelineContext"));
}
}
@Test
public void pipeline_toString() {
String str;
// no valves
assertEquals("Pipeline[]", pipeline.toString());
// with valves
pipeline = createPipeline(new LogValve(), new LogValve(), new LogValve());
str = "";
str += "Pipeline [\n";
str += " [1/3] LogValve\n";
str += " [2/3] LogValve\n";
str += " [3/3] LogValve\n";
str += "]";
assertEquals(str, pipeline.toString());
pipeline = createPipeline(new LogValve(), new LogAndBreakValve(), new LogValve());
str = "";
str += "Pipeline [\n";
str += " [1/3] LogValve\n";
str += " [2/3] LogAndBreakValve[<null>, 0]\n";
str += " [3/3] LogValve\n";
str += "]";
assertEquals(str, pipeline.toString());
}
@Test
public void pipeline_init() throws Exception {
try {
createPipeline(new LogValve(), null, new LogValve());
fail();
} catch (IllegalArgumentException e) {
assertThat(e, exception("valves[1] == null"));
}
}
@Test
public void handle_getAttribute() throws Exception {
pipeline = createPipeline(new LogValve(), new LogAndBreakValve(), new LogValve());
PipelineInvocationHandle handle = assertInvoke(pipeline, true);
// init is null
assertNull(getFieldValue(handle, "attributes", null));
// getAttribute,不会创建attributes
assertNull(handle.getAttribute("test"));
assertNull(getFieldValue(handle, "attributes", null));
// setAttribute(null),会创建attributes
handle.setAttribute("test", null);
assertNotNull(getFieldValue(handle, "attributes", null));
assertNull(handle.getAttribute("test"));
// setAttribute(value),自动创建attributes
handle.setAttribute("test", "value");
assertNotNull(getFieldValue(handle, "attributes", null));
assertEquals("value", handle.getAttribute("test"));
// 再次invoke,context不同
handle = assertInvoke(pipeline, true);
assertNull(handle.getAttribute("test"));
}
@Test
public void handle_getAttribute_withParents() throws Exception {
final PipelineContext[] contexts = new PipelineContext[3];
final PipelineImpl p3 = createPipeline(new Valve() {
public void invoke(PipelineContext pipelineContext) throws Exception {
contexts[2] = pipelineContext;
pipelineContext.invokeNext();
}
});
final PipelineImpl p2 = createPipeline(new Valve() {
public void invoke(PipelineContext pipelineContext) throws Exception {
contexts[1] = pipelineContext;
p3.newInvocation(pipelineContext).invoke();
pipelineContext.invokeNext();
}
});
pipeline = createPipeline(new Valve() {
public void invoke(PipelineContext pipelineContext) throws Exception {
contexts[0] = pipelineContext;
p2.newInvocation(pipelineContext).invoke();
pipelineContext.invokeNext();
}
});
assertInvoke(pipeline, false);
PipelineContext c1 = contexts[0];
PipelineContext c2 = contexts[1];
PipelineContext c3 = contexts[2];
assertSame(c2, getFieldValue(c3, "parentContext", null));
assertSame(c1, getFieldValue(c2, "parentContext", null));
assertSame(null, getFieldValue(c1, "parentContext", null));
c1.setAttribute("count", 1);
assertEquals(1, c1.getAttribute("count"));
assertEquals(1, c2.getAttribute("count"));
assertEquals(1, c3.getAttribute("count"));
c2.setAttribute("count", null);
assertEquals(1, c1.getAttribute("count"));
assertEquals(null, c2.getAttribute("count"));
assertEquals(null, c3.getAttribute("count"));
c3.setAttribute("count", 3);
assertEquals(1, c1.getAttribute("count"));
assertEquals(null, c2.getAttribute("count"));
assertEquals(3, c3.getAttribute("count"));
c2.setAttribute("count", null);
assertEquals(1, c1.getAttribute("count"));
assertEquals(null, c2.getAttribute("count"));
assertEquals(3, c3.getAttribute("count"));
}
@Test
public void handle_toString() {
pipeline = createPipeline(new LogValve(), new LogValve(), new LogValve());
PipelineInvocationHandle handle = pipeline.newInvocation();
assertEquals("Executing Pipeline Valve[#0/3, level 1]", handle.toString());
}
@Test
public void handle_status() {
pipeline = createPipeline(new LogValve(), new LogValve(), new LogValve());
// init status
PipelineInvocationHandle handle = pipeline.newInvocation();
assertFalse(handle.isBroken());
assertFalse(handle.isFinished());
// finish status
handle.invoke();
assertFalse(handle.isBroken());
assertTrue(handle.isFinished());
// broken status
pipeline = createPipeline(new LogValve(), new LogAndBreakValve(), new LogValve());
handle = pipeline.newInvocation();
handle.invoke();
assertTrue(handle.isBroken());
assertFalse(handle.isFinished());
}
@Test
public void invoke_uninited() {
try {
new PipelineImpl().newInvocation().invoke();
fail();
} catch (IllegalStateException e) {
assertThat(e, exception("has not been initialized"));
}
}
@Test
public void invoke_noValves() throws Exception {
// invoke
assertInvoke(pipeline, false);
assertLog();
// invoke again
assertInvoke(pipeline, false);
assertLog();
}
@Test
public void invoke_simple() throws Exception {
pipeline = createPipeline(new LogValve(), new LogValve(), new LogValve());
assertInvoke(pipeline, false);
assertLog("1-1", "1-2", "1-3");
}
@Test
public void invoke_alreadyInvoked() throws Exception {
class InvokeMultipleTimes extends LogValve {
@Override
public void invoke(PipelineContext pipelineContext) {
super.invoke(pipelineContext);
// invoke 2nd times, catched IllegalStateException
try {
pipelineContext.invokeNext();
fail();
} catch (IllegalStateException e) {
assertThat(e, exception("Valve[#3/3, level 1] has already been invoked: LogValve"));
}
// invoke 3rd times, throws out PipelineException
pipelineContext.invokeNext();
}
}
pipeline = createPipeline(new LogValve(), new InvokeMultipleTimes(), new LogValve());
try {
pipeline.newInvocation().invoke();
fail();
} catch (PipelineException e) {
assertThat(e,
exception(IllegalStateException.class, "Valve[#3/3, level 1] has already been invoked: LogValve"));
}
assertLog("1-1", "1-2", "1-3");
}
@Test
public void invoke_subPipeline() throws Exception {
Pipeline p3 = createPipeline(new LogValve(), new LogValve(), new LogValve());
Pipeline p2 = createPipeline(new LogValve(), new LogAndInvokeSubValve(p3), new LogValve());
pipeline = createPipeline(new LogValve(), new LogAndInvokeSubValve(p2), new LogValve());
// invoke
assertInvoke(pipeline, false);
assertLog("1-1", "1-2", "2-1", "2-2", "3-1", "3-2", "3-3", "2-3", "1-3");
}
@Test
public void invoke_again() throws Exception {
pipeline = createPipeline(new LogValve(), new LogValve(), new LogValve());
PipelineInvocationHandle handle = pipeline.newInvocation();
handle.invoke();
handle.invoke(); // again
assertLog("1-1", "1-2", "1-3", "1-1", "1-2", "1-3");
}
@Test
public void invoke_brokenPipeline() throws Exception {
pipeline = createPipeline(new LogValve(), new LogAndBreakValve(), new LogValve());
PipelineInvocationHandle handle = assertInvoke(pipeline, true);
try {
handle.invoke();
fail();
} catch (IllegalStateException e) {
assertThat(e, exception("cannot reinvoke a broken pipeline"));
}
}
@Test
public void invoke_simpleReturn() {
pipeline = createPipeline(new LogValve(), new LogAndReturnValve(), new LogValve());
// invoke
PipelineInvocationHandle handle = pipeline.newInvocation();
handle.invoke();
assertFalse(handle.isBroken());
assertFalse(handle.isFinished());
assertLog("1-1", "1-2");
// invoke again
handle = pipeline.newInvocation();
handle.invoke();
assertFalse(handle.isBroken());
assertFalse(handle.isFinished());
assertLog("1-1", "1-2");
}
@Test
public void break_simple() throws Exception {
pipeline = createPipeline(new LogValve(), new LogAndBreakValve(), new LogValve());
// invoke
assertInvoke(pipeline, true);
assertLog("1-1", "1-2");
// invoke again
assertInvoke(pipeline, true);
assertLog("1-1", "1-2");
}
@Test
public void break_levels_outOfBounds() throws Exception {
PipelineImpl p3 = createPipeline(new LogValve(), new LogValve(), new LogValve());
PipelineImpl p2 = createPipeline(new LogValve(), new LogAndInvokeSubValve(p3), new LogValve());
pipeline = createPipeline(new LogValve(), new LogAndInvokeSubValve(p2), new LogValve());
// break levels=3
p3.getValves()[1] = new LogAndBreakValve(3);
try {
pipeline.newInvocation().invoke();
fail();
} catch (PipelineException e) {
assertThat(
e,
exception(IllegalArgumentException.class, "Failed to invoke Valve[#2/3, level 3]",
"invalid break levels: 3, should be in range of [0, 3)"));
}
// break levels=-1
p3.getValves()[1] = new LogAndBreakValve(-1);
try {
pipeline.newInvocation().invoke();
fail();
} catch (PipelineException e) {
assertThat(
e,
exception(IllegalArgumentException.class, "Failed to invoke Valve[#2/3, level 3]",
"invalid break levels: -1, should be in range of [0, 3)"));
}
}
@Test
public void break_levels() throws Exception {
PipelineImpl p3 = createPipeline(new LogValve(), new LogValve(), new LogValve());
PipelineImpl p2 = createPipeline(new LogValve(), new LogAndInvokeSubValve(p3), new LogValve());
pipeline = createPipeline(new LogValve(), new LogAndInvokeSubValve(p2), new LogValve());
// break levels=2
p3.getValves()[1] = new LogAndBreakValve(2);
assertInvoke(pipeline, true);
assertLog("1-1", "1-2", "2-1", "2-2", "3-1", "3-2"/* break */);
// break levels=1
p3.getValves()[1] = new LogAndBreakValve(1);
assertInvoke(pipeline, false);
assertLog("1-1", "1-2", "2-1", "2-2", "3-1", "3-2"/* break */, "1-3");
// break levels=0
p3.getValves()[1] = new LogAndBreakValve(0);
assertInvoke(pipeline, false);
assertLog("1-1", "1-2", "2-1", "2-2", "3-1", "3-2"/* break */, "2-3", "1-3");
}
@Test
public void break_label_empty() throws Exception {
pipeline = createPipeline(new LogAndBreakValve(" "));
try {
pipeline.newInvocation().invoke();
fail();
} catch (PipelineException e) {
assertThat(e, exception(IllegalArgumentException.class, "no label"));
}
pipeline = createPipeline(new LogAndBreakValve(null));
try {
pipeline.newInvocation().invoke();
fail();
} catch (PipelineException e) {
assertThat(e, exception(IllegalArgumentException.class, "no label"));
}
}
@Test
public void break_label_NotFound() throws Exception {
PipelineImpl p3 = createPipeline(new LogValve(), new LogAndBreakValve(" mylabel "), new LogValve());
PipelineImpl p2 = createPipeline(new LogValve(), new LogAndInvokeSubValve(p3), new LogValve());
pipeline = createPipeline(new LogValve(), new LogAndInvokeSubValve(p2), new LogValve());
pipeline.setLabel("mylabel2");
// invoke
try {
pipeline.newInvocation().invoke();
fail();
} catch (LabelNotDefinedException e) {
assertThat(e, exception("Could not find pipeline or sub-pipeline with label \"mylabel\" "
+ "in the pipeline invocation stack"));
}
}
@Test
public void break_label() throws Exception {
PipelineImpl p3 = createPipeline(new LogValve(), new LogAndBreakValve(" mylabel "), new LogValve());
PipelineImpl p2 = createPipeline(new LogValve(), new LogAndInvokeSubValve(p3), new LogValve());
pipeline = createPipeline(new LogValve(), new LogAndInvokeSubValve(p2), new LogValve());
// levels = 2
pipeline.setLabel("mylabel");
assertInvoke(pipeline, true);
assertLog("1-1", "1-2", "2-1", "2-2", "3-1", "3-2"/* break */);
// levels = 1
p2.setLabel("mylabel");
assertInvoke(pipeline, false);
assertLog("1-1", "1-2", "2-1", "2-2", "3-1", "3-2"/* break */, "1-3");
// levels = 0
p3.setLabel("mylabel");
assertInvoke(pipeline, false);
assertLog("1-1", "1-2", "2-1", "2-2", "3-1", "3-2"/* break */, "2-3", "1-3");
}
@Test
public void break_toTop() throws Exception {
PipelineImpl p3 = createPipeline(new LogValve(), new LogAndBreakValve(" #TOP "), new LogValve());
PipelineImpl p2 = createPipeline(new LogValve(), new LogAndInvokeSubValve(p3), new LogValve());
pipeline = createPipeline(new LogValve(), new LogAndInvokeSubValve(p2), new LogValve());
// levels = 2
assertInvoke(pipeline, true);
assertLog("1-1", "1-2", "2-1", "2-2", "3-1", "3-2"/* break */);
}
}