Mercurial > stress-tester
changeset 531:229736339e0c
HttpMvelFilter improvements
author | Devel 2 |
---|---|
date | Fri, 01 Sep 2017 09:59:19 +0200 |
parents | ab132a470e21 |
children | f78f71168bef |
files | stress-tester/src/main/java/com/passus/st/client/http/filter/HttpFilterDirection.java stress-tester/src/main/java/com/passus/st/client/http/filter/HttpMvelFilter.java stress-tester/src/main/java/com/passus/st/config/StringSourceNodeDefinition.java stress-tester/src/main/java/com/passus/st/config/StringToExecutableStatementValueTransformer.java stress-tester/src/test/java/com/passus/st/client/http/filter/HttpMvelFilterTest.java stress-tester/src/test/java/com/passus/st/config/StringSourceNodeDefinitionTest.java |
diffstat | 6 files changed, 153 insertions(+), 210 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpFilterDirection.java Fri Sep 01 09:59:19 2017 +0200 @@ -0,0 +1,11 @@ +package com.passus.st.client.http.filter; + +/** + * + * @author Mirosław Hawrot + */ +public enum HttpFilterDirection { + + IN, OUT, BOTH + +}
--- a/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpMvelFilter.java Thu Aug 31 15:32:31 2017 +0200 +++ b/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpMvelFilter.java Fri Sep 01 09:59:19 2017 +0200 @@ -1,50 +1,37 @@ package com.passus.st.client.http.filter; -import com.passus.commons.ConversionException; +import com.passus.commons.Assert; import com.passus.commons.annotations.Plugin; -import com.passus.config.CMapNode; -import com.passus.config.CNode; -import com.passus.config.CTupleNode; -import com.passus.config.CValueNode; import com.passus.config.Configuration; -import com.passus.config.ValueTransformer; import com.passus.config.annotations.NodeDefinitionCreate; import static com.passus.config.schema.ConfigurationSchemaBuilder.mapDef; -import static com.passus.config.schema.ConfigurationSchemaBuilder.mixedDef; import static com.passus.config.schema.ConfigurationSchemaBuilder.tupleDef; -import static com.passus.config.schema.ConfigurationSchemaBuilder.valueDef; -import com.passus.config.schema.MixedNodeDefinition; +import static com.passus.config.schema.ConfigurationSchemaBuilder.enumDef; import com.passus.config.schema.NodeDefinition; import com.passus.config.schema.NodeDefinitionCreator; -import com.passus.config.schema.NodeTransformer; -import com.passus.config.validation.Errors; import com.passus.net.http.HttpRequest; import com.passus.net.http.HttpResponse; import com.passus.st.client.http.HttpFlowContext; +import static com.passus.st.client.http.filter.HttpFilter.ACCEPT; +import static com.passus.st.client.http.filter.HttpFilter.DENY; +import static com.passus.st.client.http.filter.HttpFilter.DUNNO; +import com.passus.st.config.StringSourceNodeDefinition; +import com.passus.st.config.StringToExecutableStatementValueTransformer; import com.passus.st.plugin.PluginConstants; -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.Collection; import java.util.HashMap; -import java.util.List; import java.util.Map; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.mvel2.CompileException; -import org.mvel2.MVEL; import org.mvel2.compiler.ExecutableStatement; import org.mvel2.integration.VariableResolverFactory; import org.mvel2.integration.impl.CachingMapVariableResolverFactory; -import org.mvel2.integration.impl.MapVariableResolverFactory; /** * - * @author mikolaj.podbielski + * @author Mirosław Hawrot */ +@NodeDefinitionCreate(HttpMvelFilter.HttpMvelFilterNodeDefCreator.class) @Plugin(name = HttpMvelFilter.TYPE, category = PluginConstants.CATEGORY_HTTP_FILTER) -@NodeDefinitionCreate(HttpMvelFilter.NodeDefCreator.class) public class HttpMvelFilter extends HttpFilter { public static final String TYPE = "mvel"; @@ -52,58 +39,61 @@ private static final Logger LOGGER = LogManager.getLogger(HttpMvelFilter.class); private VariableResolverFactory globalFactory; - private ExecutableStatement outbound; - private ExecutableStatement inbound; - VariableResolverFactory getGlobalFactory() { + private ExecutableStatement statement; + + private HttpFilterDirection direction = HttpFilterDirection.OUT; + + public HttpMvelFilter() { + } + + public HttpMvelFilter(ExecutableStatement statement, HttpFilterDirection direction) { + Assert.notNull(statement, "statement"); + Assert.notNull(direction, "direction"); + this.statement = statement; + this.direction = direction; + } + + public VariableResolverFactory getGlobalFactory() { return globalFactory; } - void setGlobalFactory(VariableResolverFactory globalFactory) { + public void setGlobalFactory(VariableResolverFactory globalFactory) { this.globalFactory = globalFactory; } - ExecutableStatement getOutbound() { - return outbound; + public HttpFilterDirection getDirection() { + return direction; } - void setOutbound(ExecutableStatement outbound) { - this.outbound = outbound; + public void setDirection(HttpFilterDirection direction) { + Assert.notNull(direction, "direction"); + this.direction = direction; } - ExecutableStatement getInbound() { - return inbound; + public ExecutableStatement getStatement() { + return statement; } - void setInbound(ExecutableStatement inbound) { - this.inbound = inbound; + public void setStatement(ExecutableStatement statement) { + this.statement = statement; } @Override public void configure(Configuration config) { - outbound = (ExecutableStatement) config.get("outbound", null); - inbound = (ExecutableStatement) config.get("inbound", null); + direction = (HttpFilterDirection) config.get("dir", HttpFilterDirection.OUT); + statement = (ExecutableStatement) config.get("script"); } - @Override - public int filterOutbound(HttpRequest request, HttpResponse resp, HttpFlowContext context) { - return filter(outbound, request, resp, context); - } - - @Override - public int filterInbound(HttpRequest request, HttpResponse resp, HttpFlowContext context) { - return filter(inbound, request, resp, context); - } - - private int filter(ExecutableStatement expression, HttpRequest request, HttpResponse resp, HttpFlowContext context) { - if (expression == null) { + private int filter(HttpRequest req, HttpResponse resp, HttpFlowContext context) { + if (statement == null) { return DUNNO; } Map<String, Object> vars = new HashMap<>(3); - vars.put("$req", request); + vars.put("$req", req); vars.put("$resp", resp); - vars.put("$ctx", context); + vars.put("$context", context); CachingMapVariableResolverFactory factory = new CachingMapVariableResolverFactory(vars); if (globalFactory != null) { @@ -111,146 +101,58 @@ } try { - Object out = expression.getValue(null, factory); + Object out = statement.getValue(null, factory); if (out instanceof Integer) { int value = (Integer) out; - if (value == DENY || value == DUNNO || value == ACCEPT) { - return value; + if (value < 0) { + return DENY; + } else if (value > 0) { + return ACCEPT; } + + return DUNNO; } } catch (Throwable th) { LOGGER.trace(th); } + return DUNNO; } - public static ExecutableStatement compile(String expression) { - try { - return (ExecutableStatement) MVEL.compileExpression(expression); - } catch (Exception ex) { - LOGGER.warn("Compilation error:\n" + ex.getMessage()); - throw ex; + @Override + public int filterOutbound(HttpRequest req, HttpResponse resp, HttpFlowContext context) { + if (direction == HttpFilterDirection.BOTH || direction == HttpFilterDirection.OUT) { + return filter(req, resp, context); } - } - - public static void validate(String expression) throws CompileException { - MVEL.compileExpression(expression); - } - public static int validate(Collection<String> includes) throws CompileException, RuntimeException { - Map variables = new HashMap(); - MapVariableResolverFactory globalFactory = new MapVariableResolverFactory(variables); - for (String include : includes) { - ExecutableStatement es = (ExecutableStatement) MVEL.compileExpression(include); - es.getValue(null, globalFactory); - } - return variables.size(); - } - - public static VariableResolverFactory global(Collection<String> includes) { - MapVariableResolverFactory globalFactory = new MapVariableResolverFactory(); -// GlobalExpressionList compiledGlobalExpressions; - for (String include : includes) { - if (include != null) { -// GlobalExpression globalExpression = compiledGlobalExpressions.getByName(include); -// if (globalExpression != null) { -// ExecutableStatement compiledGlobal = globalExpression.getCompiled(); -// compiledGlobal.getValue(null, globalFactory); -// } - } - } - return globalFactory; + return DUNNO; } @Override - public HttpMvelFilter instanceForWorker(int index) { - HttpMvelFilter filter = new HttpMvelFilter(); - filter.globalFactory = globalFactory; - filter.outbound = outbound; - filter.inbound = inbound; - return filter; + public int filterInbound(HttpRequest req, HttpResponse resp, HttpFlowContext context) { + if (direction == HttpFilterDirection.BOTH || direction == HttpFilterDirection.IN) { + return filter(req, resp, context); + } + + return DUNNO; } - // TODO: replace ScriptNodeTransformer and ScriptTransformer with custom NodeDefinition - public static class NodeDefCreator implements NodeDefinitionCreator { + @Override + public HttpFilter instanceForWorker(int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + public static final class HttpMvelFilterNodeDefCreator implements NodeDefinitionCreator { @Override public NodeDefinition create() { - MixedNodeDefinition scriptDef = mixedDef( - valueDef().setTransformer(new ScriptTransformer()), - mapDef(tupleDef("file", valueDef())).setTransformer(new ScriptNodeTransformer()) - ); - return mapDef( - // tupleDef("includes", null), - tupleDef("outbound", scriptDef), - tupleDef("inbound", scriptDef) + tupleDef("dir", enumDef(HttpFilterDirection.class)).setRequired(false), + tupleDef("script", new StringSourceNodeDefinition() + .setTransformer(new StringToExecutableStatementValueTransformer()) + ) ); } } - - private static class ScriptNodeTransformer implements NodeTransformer<CValueNode> { - - @Override - public CValueNode transform(CNode node, Errors errors) { - CMapNode mapNode = (CMapNode) node; - - List<CTupleNode> tuples = mapNode.getChildren(); - if (tuples.size() != 1) { - errors.reject(node, "Node should contain one child."); - return null; - } - - String script = null; - - CTupleNode tupleNode = tuples.get(0); - CValueNode valueNode = (CValueNode) tupleNode.getNode(); - switch (tupleNode.getName()) { - case "file": - String fileName = (String) valueNode.getValue(); - try { - script = new String(Files.readAllBytes(Paths.get(new File(fileName).toURI()))); - } catch (IOException ex) { - errors.reject(valueNode, "Could not read file \"%s\".", fileName); - } - break; - case "script": - script = (String) valueNode.getValue(); - break; - default: - errors.reject(tupleNode, "Invalid key."); - } - - if (script != null) { - ExecutableStatement es = compile(script); - return new CValueNode(es); - } else { - return new CValueNode(null); - } - } - - @Override - public CValueNode reverseTransform(CNode node, Errors errors) { - throw new UnsupportedOperationException("Not supported yet."); - } - - } - - private static class ScriptTransformer implements ValueTransformer { - - @Override - public Object transform(Object obj) throws ConversionException { - if (obj instanceof String) { - return compile((String) obj); - } - throw new ConversionException("Invalid token store type."); - } - - @Override - public Object reverseTransform(Object obj) throws ConversionException { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - } }
--- a/stress-tester/src/main/java/com/passus/st/config/StringSourceNodeDefinition.java Thu Aug 31 15:32:31 2017 +0200 +++ b/stress-tester/src/main/java/com/passus/st/config/StringSourceNodeDefinition.java Fri Sep 01 09:59:19 2017 +0200 @@ -1,5 +1,6 @@ package com.passus.st.config; +import com.passus.commons.ConversionException; import com.passus.commons.utils.ArrayUtils; import com.passus.config.CMapNode; import com.passus.config.CNode; @@ -8,10 +9,12 @@ import static com.passus.config.ConfigurationUtils.extractString; import static com.passus.config.ConfigurationUtils.validateType; import com.passus.config.NodeType; +import com.passus.config.ValueTransformer; import com.passus.config.schema.NodeDefinition; import static com.passus.config.schema.validation.NodeValidationMessages.ONE_CHILD_REQUIRED_MSG; import static com.passus.config.schema.validation.NodeValidationMessages.TUPLE_NOT_DEFINED_MSG; import com.passus.config.validation.Errors; +import static com.passus.config.validation.ValidationDefaultMessages.GENERAL_CONVERSION_ERROR; import static com.passus.config.validation.ValidationDefaultMessages.VALUE_SHOULD_NOT_BE_NULL_MSG; import java.io.File; import java.io.IOException; @@ -25,10 +28,10 @@ */ public class StringSourceNodeDefinition extends NodeDefinition<StringSourceNodeDefinition> { - public static final StringSourceNodeDefinition INSTANCE = new StringSourceNodeDefinition(); - private final static Set<Class<? extends CNode>> SUPPORTED = ArrayUtils.asUnmodifiableSet(CValueNode.class, CMapNode.class); + private ValueTransformer transformer; + @Override public Set<Class<? extends CNode>> getSupportedNode() { return SUPPORTED; @@ -69,11 +72,21 @@ } } + public ValueTransformer getTransformer() { + return transformer; + } + + public StringSourceNodeDefinition setTransformer(ValueTransformer transformer) { + this.transformer = transformer; + return this; + } + @Override protected CNode doTransform(CNode node, Errors errors, boolean reverse) { if (reverse) { throw new UnsupportedOperationException("Not supported yet."); } else { + CValueNode outNode = null; if (node.getType() == NodeType.MAP) { CMapNode mapNode = (CMapNode) node; CTupleNode tuple = mapNode.getFirstChild(); @@ -81,7 +94,7 @@ try { errors.pushNestedPath(tuple.getName()); if (tupleName.equalsIgnoreCase("$text")) { - return tuple.getNode(); + outNode = (CValueNode) tuple.getNode(); } else if (tupleName.equalsIgnoreCase("$file")) { String fileName = extractString(tuple, errors); if (fileName != null) { @@ -93,7 +106,7 @@ } else { try { String content = FileUtils.readFileToString(file); - return new CValueNode(content); + outNode = new CValueNode(content); } catch (IOException ex) { errors.reject(tuple.getNode(), "Error occured during reading the file."); } @@ -103,6 +116,21 @@ } finally { errors.popNestedPath(); } + } else if (node.getType() == NodeType.VALUE) { + outNode = (CValueNode) node; + } + + if (outNode != null) { + if (transformer != null) { + try { + Object newValue = transformer.transform(outNode.getValue()); + outNode.setValue(newValue); + } catch (ConversionException e) { + errors.reject(node, GENERAL_CONVERSION_ERROR); + } + } + + return outNode; } return node;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stress-tester/src/main/java/com/passus/st/config/StringToExecutableStatementValueTransformer.java Fri Sep 01 09:59:19 2017 +0200 @@ -0,0 +1,33 @@ +package com.passus.st.config; + +import com.passus.commons.ConversionException; +import com.passus.config.ValueTransformer; +import org.mvel2.MVEL; +import org.mvel2.compiler.ExecutableStatement; + +/** + * + * @author Mirosław Hawrot + */ +public class StringToExecutableStatementValueTransformer implements ValueTransformer { + + @Override + public Object transform(Object obj) throws ConversionException { + if (obj == null) { + return null; + } + + String str = obj.toString(); + try { + return (ExecutableStatement) MVEL.compileExpression(str); + } catch (Exception ex) { + throw new ConversionException("Compilation error:\n" + ex.getMessage()); + } + } + + @Override + public Object reverseTransform(Object obj) throws ConversionException { + throw new UnsupportedOperationException("Not supported yet."); + } + +}
--- a/stress-tester/src/test/java/com/passus/st/client/http/filter/HttpMvelFilterTest.java Thu Aug 31 15:32:31 2017 +0200 +++ b/stress-tester/src/test/java/com/passus/st/client/http/filter/HttpMvelFilterTest.java Fri Sep 01 09:59:19 2017 +0200 @@ -5,10 +5,6 @@ import com.passus.net.http.HttpMethod; import com.passus.net.http.HttpRequest; import com.passus.net.http.HttpRequestBuilder; -import com.passus.net.http.HttpResponse; -import com.passus.net.http.HttpResponseBuilder; -import com.passus.st.ParametersBag; -import com.passus.st.client.http.HttpFlowContext; import java.io.File; import java.util.List; import org.mvel2.MVEL; @@ -30,7 +26,7 @@ + "$req.getUri().toString().equals(\"/index.html\") ? 1 : 0"; HttpMvelFilter filter = new HttpMvelFilter(); - filter.setOutbound(es(expression)); + filter.setStatement(es(expression)); int result = filter.filterOutbound(req, null, null); @@ -39,41 +35,13 @@ } @Test - public void testFilterInbound() { - HttpRequest req = HttpRequestBuilder.get("http://example.com/index.html").build(); - HttpResponse resp = HttpResponseBuilder.ok().cookie("id", "123").build(); - HttpFlowContext mockContext = HttpFilterTestUtils.createMockContext(); - HttpFilterTestUtils.tagMessages(req, resp); - - String expression = "hlp = com.passus.net.http.HttpMessageHelper.STRICT;\n" - + "c = hlp.getCookie($resp, \"id\");\n" - + "if (c != null) {\n" - + " $ctx.scopes().getSession($req).set(\"token\", c.getValue());\n" - + "}"; - - HttpMvelFilter filter = new HttpMvelFilter(); - filter.setInbound(es(expression)); - - int result = filter.filterInbound(req, resp, mockContext); - ParametersBag session = mockContext.scopes().getSession(req); - - assertEquals(0, result); - assertEquals("123", session.get("token").toString()); - } - -// @Test -// public void testGlobal() { -// } - @Test public void testConfigure() throws Exception { File file = ResourceUtils.getFile("mvel/return1.mvel"); String filterConfig = "filters:\n" + " - type: mvel\n" - + " outbound:\n" - + " \"return -1\"\n" - + " inbound:\n" - + " file: '" + file.getAbsolutePath() + "'"; + + " dir: out\n" + + " script: return -1\n"; Errors errors = new Errors(); List<HttpFilter> filters = HttpFiltersConfigurator.getFilters(filterConfig, errors); @@ -85,7 +53,7 @@ HttpMvelFilter filter = (HttpMvelFilter) filters.get(0); assertEquals(-1, filter.filterOutbound(null, null, null)); - assertEquals(1, filter.filterInbound(null, null, null)); + assertEquals(0, filter.filterInbound(null, null, null)); } private static ExecutableStatement es(String expression) {
--- a/stress-tester/src/test/java/com/passus/st/config/StringSourceNodeDefinitionTest.java Thu Aug 31 15:32:31 2017 +0200 +++ b/stress-tester/src/test/java/com/passus/st/config/StringSourceNodeDefinitionTest.java Fri Sep 01 09:59:19 2017 +0200 @@ -85,10 +85,11 @@ + " content3: {$file: \"" + mvelFile.getAbsolutePath().replace("\\", "\\\\") + "\"}\n" ); + StringSourceNodeDefinition strSourceDef = new StringSourceNodeDefinition(); KeyNameVaryListNodeDefinition listDef = keyNameVaryListDef() - .add("content1", StringSourceNodeDefinition.INSTANCE) - .add("content2", StringSourceNodeDefinition.INSTANCE) - .add("content3", StringSourceNodeDefinition.INSTANCE); + .add("content1", strSourceDef) + .add("content2", strSourceDef) + .add("content3", strSourceDef); MapNodeDefinition rootNodeDef = mapDef( tupleDef("list", listDef)