Mercurial > stress-tester
changeset 491:b838d00420df
HttpResponseContentExtractorFilter
author | Devel 1 |
---|---|
date | Fri, 11 Aug 2017 10:32:25 +0200 |
parents | df8db8c1a760 |
children | f7ad421d783b |
files | stress-tester/src/main/java/com/passus/st/client/http/filter/HttpResponseContentExtractorFilter.java stress-tester/src/main/java/com/passus/st/client/http/filter/HttpResponseContentExtractorFilterTransformer.java stress-tester/src/test/java/com/passus/st/client/http/filter/HttpFilterTestUtils.java stress-tester/src/test/java/com/passus/st/client/http/filter/HttpResponseContentExtractorFilterTest.java stress-tester/src/test/java/com/passus/st/client/http/filter/HttpScopeModificationFilterTest.java |
diffstat | 5 files changed, 494 insertions(+), 12 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/HttpResponseContentExtractorFilter.java Fri Aug 11 10:32:25 2017 +0200 @@ -0,0 +1,197 @@ +package com.passus.st.client.http.filter; + +import com.passus.commons.Assert; +import com.passus.commons.annotations.Plugin; +import com.passus.config.Configuration; +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 static com.passus.config.schema.ConfigurationSchemaBuilder.valueDefBool; +import com.passus.config.schema.KeyNameVaryListNodeDefinition; +import com.passus.config.schema.MapNodeDefinition; +import com.passus.config.schema.MixedNodeDefinition; +import com.passus.config.schema.NodeDefinition; +import com.passus.config.schema.NodeDefinitionCreator; +import com.passus.net.http.HttpRequest; +import com.passus.net.http.HttpResponse; +import com.passus.st.ParametersBag; +import com.passus.st.client.http.HttpFlowContext; +import com.passus.st.client.http.extractor.ContentExtractor; +import com.passus.st.config.HeaderOperationNodeDefinition; +import com.passus.st.plugin.PluginConstants; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +/** + * + * @author mikolaj.podbielski + */ +@Plugin(name = HttpResponseContentExtractorFilter.TYPE, category = PluginConstants.CATEGORY_HTTP_FILTER) +@NodeDefinitionCreate(HttpResponseContentExtractorFilter.NodeDefCreator.class) +public class HttpResponseContentExtractorFilter extends HttpFilter { + + public static final String TYPE = "responseContentExtractor"; + + public static abstract class Operation { + + public abstract void process(HttpResponse response, HttpFlowContext context); + } + + public static abstract class SetScopeParamOperation extends Operation { + + protected final String paramName; + protected final ContentExtractor contentExtractor; + protected final boolean checkValueExists; + + public SetScopeParamOperation(String paramName, ContentExtractor contentExtractor, boolean checkValueExists) { + this.paramName = paramName; + this.contentExtractor = contentExtractor; + this.checkValueExists = checkValueExists; + } + } + + public static class SetSessionParamOperation extends SetScopeParamOperation { + + protected final boolean autocreate; + + public SetSessionParamOperation(String paramName, ContentExtractor contentExtractor, boolean checkValueExists) { + this(paramName, contentExtractor, checkValueExists, true); + } + + public SetSessionParamOperation(String paramName, ContentExtractor contentExtractor, boolean checkValueExists, boolean autocreate) { + super(paramName, contentExtractor, checkValueExists); + this.autocreate = autocreate; + } + + @Override + public void process(HttpResponse response, HttpFlowContext context) { + ParametersBag params = context.scopes().getSession(response, autocreate); + if (params != null) { + if (checkValueExists && params.contains(paramName)) { + return; + } + + try { + String value = contentExtractor.extract(response); + params.set(paramName, value); + } catch (IOException ex) { + LOGGER.info("Could not read message body", ex); + } + } + } + } + + public static class SetGlobalParamOperation extends SetScopeParamOperation { + + public SetGlobalParamOperation(String paramName, ContentExtractor contentExtractor, boolean checkValueExists) { + super(paramName, contentExtractor, checkValueExists); + } + + @Override + public void process(HttpResponse response, HttpFlowContext context) { + ParametersBag params = context.scopes().getGlobal(); + if (checkValueExists && params.contains(paramName)) { + return; + } + + try { + String value = contentExtractor.extract(response); + params.set(paramName, value); + } catch (IOException ex) { + LOGGER.info("Could not read message body", ex); + } + } + } + + private static final Logger LOGGER = LogManager.getLogger(HttpResponseContentExtractorFilter.class); + + private HttpMessagePredicate predicate; + private List<Operation> operations = new ArrayList<>(); + + public void addOperation(Operation operation) { + Assert.notNull(operation, "operation"); + operations.add(operation); + } + + HttpMessagePredicate getPredicate() { + return predicate; + } + + List<Operation> getOperations() { + return operations; + } + + @Override + public void configure(Configuration config) { + List<Operation> ops = (List<Operation>) config.get("operations"); + operations.clear(); + + if (ops != null) { + for (Operation op : ops) { + addOperation(op); + } + } + + predicate = (HttpMessagePredicate) config.get("applyIf", null); + } + + @Override + public int filterInbound(HttpRequest request, HttpResponse resp, HttpFlowContext context) { + if (resp != null && !operations.isEmpty()) { + boolean exec = true; + if (predicate != null) { + HttpMessageWrapper wrapper = new HttpMessageWrapper(request, resp, context); + exec = predicate.test(wrapper); + } + + if (exec) { + for (Operation op : operations) { + op.process(resp, context); + } + } + } + return DUNNO; + } + + @Override + public HttpResponseContentExtractorFilter instanceForWorker(int index) { + HttpResponseContentExtractorFilter filter = new HttpResponseContentExtractorFilter(); + filter.predicate = predicate; + filter.operations.addAll(operations); + return filter; + } + + public static class NodeDefCreator implements NodeDefinitionCreator { + + @Override + public NodeDefinition create() { + // TODO: jak pozwolić na dokładnie jedno z poniższych + MapNodeDefinition mapDef = mapDef( + tupleDef("$regex", valueDef()).setRequired(false), + tupleDef("$xpath", valueDef()).setRequired(false) + ); + + HeaderOperationNodeDefinition setSessionDef = new HeaderOperationNodeDefinition(mapDef); + setSessionDef.addParam(tupleDef("@autocreate", valueDefBool()).setRequired(false)); + + HeaderOperationNodeDefinition setGlobalDef = new HeaderOperationNodeDefinition(mapDef); + + KeyNameVaryListNodeDefinition operationsDef = new KeyNameVaryListNodeDefinition() + .setNodeTransformer(new HttpResponseContentExtractorFilterTransformer()) + .add("$addSessionParam", setSessionDef) + .add("$setSessionParam", setSessionDef) + .add("$addGlobalParam", setGlobalDef) + .add("$setGlobalParam", setGlobalDef); + + return mapDef( + tupleDef("operations", operationsDef), + tupleDef("applyIf", new HttpFilterMessagePredicateNodeDefinition()).setRequired(false) + ); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stress-tester/src/main/java/com/passus/st/client/http/filter/HttpResponseContentExtractorFilterTransformer.java Fri Aug 11 10:32:25 2017 +0200 @@ -0,0 +1,145 @@ +package com.passus.st.client.http.filter; + +import com.passus.config.CMapNode; +import com.passus.config.CNode; +import com.passus.config.CTupleNode; +import com.passus.config.CValueNode; +import static com.passus.config.ConfigurationUtils.extractBoolean; +import com.passus.config.NodeType; +import com.passus.config.schema.NodeTransformer; +import com.passus.config.validation.Errors; +import com.passus.st.client.http.extractor.ContentExtractor; +import com.passus.st.client.http.extractor.ContentExtractorTransformer; +import com.passus.st.client.http.filter.HttpResponseContentExtractorFilter.Operation; +import com.passus.st.client.http.filter.HttpResponseContentExtractorFilter.SetGlobalParamOperation; +import com.passus.st.client.http.filter.HttpResponseContentExtractorFilter.SetSessionParamOperation; +import static com.passus.st.validation.NodeValidationUtils.validateType; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * + * @author mikolaj.podbielski + */ +public class HttpResponseContentExtractorFilterTransformer implements NodeTransformer<CValueNode> { + + private final ContentExtractorTransformer extractorTransformer = ContentExtractorTransformer.DEFAULT; + + private SetSessionParamOperation createSetSessionParamOperation(CTupleNode tuple, Errors errors, boolean checkValueExists) { + if (validateType(tuple.getNode(), NodeType.MAP, errors)) { + CMapNode mapNode = (CMapNode) tuple.getNode(); + + boolean autocreate = false; + String paramName = null; + ContentExtractor extractor = null; + for (CTupleNode mapTupleNode : mapNode.getChildren()) { + try { + errors.pushNestedPath(mapTupleNode.getName()); + switch (mapTupleNode.getName()) { + case "@autocreate": + autocreate = extractBoolean(mapTupleNode, errors); + break; + default: + try { + paramName = mapTupleNode.getName(); + extractor = extractorTransformer.transform(mapTupleNode.getNode()); + } catch (Exception e) { + errors.reject(mapTupleNode.getNode(), "Invalid expression."); + } + + } + } finally { + errors.popNestedPath(); + } + } + + return new SetSessionParamOperation(paramName, extractor, checkValueExists, autocreate); + } + + return null; + } + + private SetGlobalParamOperation createSetGlobalParamOperation(CTupleNode tuple, Errors errors, boolean checkValueExists) { + if (validateType(tuple.getNode(), NodeType.MAP, errors)) { + CMapNode mapNode = (CMapNode) tuple.getNode(); + + String paramName = null; + ContentExtractor extractor = null; + for (CTupleNode mapTupleNode : mapNode.getChildren()) { + try { + errors.pushNestedPath(mapTupleNode.getName()); + switch (mapTupleNode.getName()) { + default: + try { + paramName = mapTupleNode.getName(); + extractor = extractorTransformer.transform(mapTupleNode.getNode()); + } catch (Exception e) { + errors.reject(mapTupleNode.getNode(), "Invalid expression."); + } + + } + } finally { + errors.popNestedPath(); + } + } + + return new SetGlobalParamOperation(paramName, extractor, checkValueExists); + } + + return null; + } + + @Override + public CValueNode transform(CNode node, Errors errors) { + CMapNode mapNode = (CMapNode) node; + + List<CTupleNode> tuples = mapNode.getChildren(); + List<Operation> operations; + if (tuples.isEmpty()) { + operations = Collections.EMPTY_LIST; + } else { + operations = new ArrayList<>(); + } + + for (CTupleNode tuple : tuples) { + String opName = tuple.getName(); + + try { + errors.pushNestedPath(opName); + Operation op = null; + switch (opName.toLowerCase()) { + case "$addsessionparam": + op = createSetSessionParamOperation(tuple, errors, true); + break; + case "$setsessionparam": + op = createSetSessionParamOperation(tuple, errors, false); + break; + case "$addglobalparam": + op = createSetGlobalParamOperation(tuple, errors, true); + break; + case "$setglobalparam": + op = createSetGlobalParamOperation(tuple, errors, false); + break; + default: + throw new IllegalStateException("Not supported operation '" + opName + "'."); + + } + + if (op != null) { + operations.add(op); + } + } finally { + errors.popNestedPath(); + } + } + + return new CValueNode(operations); + } + + @Override + public CValueNode reverseTransform(CNode node, Errors errors) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + +}
--- a/stress-tester/src/test/java/com/passus/st/client/http/filter/HttpFilterTestUtils.java Thu Aug 10 14:03:21 2017 +0200 +++ b/stress-tester/src/test/java/com/passus/st/client/http/filter/HttpFilterTestUtils.java Fri Aug 11 10:32:25 2017 +0200 @@ -1,9 +1,12 @@ package com.passus.st.client.http.filter; +import com.passus.config.validation.Errors; +import com.passus.config.validation.ObjectError; import com.passus.net.http.HttpMessage; import static com.passus.st.client.http.HttpConsts.TAG_SESSION_ID; import com.passus.st.client.http.HttpFlowContext; import com.passus.st.client.http.HttpScopes; +import java.util.List; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -26,4 +29,13 @@ } } + protected static void printErrors(Errors errors) { + List<ObjectError> allErrors = errors.getAllErrors(); + if (allErrors.size() > 0) { + System.out.println("ERRORS:"); + for (ObjectError error : allErrors) { + System.out.println(error); + } + } + } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stress-tester/src/test/java/com/passus/st/client/http/filter/HttpResponseContentExtractorFilterTest.java Fri Aug 11 10:32:25 2017 +0200 @@ -0,0 +1,126 @@ +package com.passus.st.client.http.filter; + +import com.passus.config.validation.Errors; +import com.passus.net.http.HttpResponse; +import com.passus.net.http.HttpResponseBuilder; +import com.passus.st.client.http.HttpConsts; +import com.passus.st.client.http.HttpFlowContext; +import com.passus.st.client.http.HttpScopes; +import com.passus.st.client.http.extractor.ContentExtractor; +import com.passus.st.client.http.extractor.RegexValueExtractor; +import com.passus.st.client.http.extractor.XmlValueExtractor; +import static com.passus.st.client.http.filter.HttpFilterTestUtils.createMockContext; +import com.passus.st.client.http.filter.HttpResponseContentExtractorFilter.Operation; +import com.passus.st.client.http.filter.HttpResponseContentExtractorFilter.SetGlobalParamOperation; +import com.passus.st.client.http.filter.HttpResponseContentExtractorFilter.SetSessionParamOperation; +import java.util.List; +import static org.testng.AssertJUnit.*; +import org.testng.annotations.Test; + +/** + * + * @author mikolaj.podbielski + */ +public class HttpResponseContentExtractorFilterTest { + + private final String sessionId = "sessionId"; + private final ConstContentExtractor oldValue = new ConstContentExtractor("oldValue"); + private final ConstContentExtractor newValue = new ConstContentExtractor("newValue"); + + private HttpResponse createResponse() { + return HttpResponseBuilder.ok() + .tag(HttpConsts.TAG_SESSION_ID, sessionId) + .content("content") + .build(); + } + + @Test + public void testSetSessionParamOperation() { + HttpFlowContext mockContext = createMockContext(); + HttpScopes scopes = mockContext.scopes(); + HttpResponse response = createResponse(); + + HttpResponseContentExtractorFilter filter = new HttpResponseContentExtractorFilter(); + filter.addOperation(new SetSessionParamOperation("paramName", oldValue, true)); + filter.filterInbound(null, response, mockContext); + assertEquals("oldValue", scopes.getSession(sessionId, false).get("paramName")); + + filter = new HttpResponseContentExtractorFilter(); + filter.addOperation(new SetSessionParamOperation("paramName", newValue, true)); + filter.filterInbound(null, response, mockContext); + assertEquals("oldValue", scopes.getSession(sessionId, false).get("paramName")); + } + + @Test + public void testSetGlobalParamOperation() { + HttpFlowContext mockContext = createMockContext(); + HttpScopes scopes = mockContext.scopes(); + HttpResponse response = createResponse(); + + HttpResponseContentExtractorFilter filter = new HttpResponseContentExtractorFilter(); + filter.addOperation(new SetGlobalParamOperation("paramName", oldValue, true)); + filter.filterInbound(null, response, mockContext); + assertEquals("oldValue", scopes.getGlobal().get("paramName")); + + filter = new HttpResponseContentExtractorFilter(); + filter.addOperation(new SetGlobalParamOperation("paramName", newValue, true)); + filter.filterInbound(null, response, mockContext); + assertEquals("oldValue", scopes.getGlobal().get("paramName")); + } + + @Test + public void testConfigure() throws Exception { + String filterConfig = "filters:\n" + + " - type: responseContentExtractor\n" + + " applyIf:\n" + + " \"req.uri\": {$contains: \"/pydio/\"}\n" + + " operations:\n" + + " $setSessionParam:\n" + + " \"@autocreate\": true\n" + + " SecureToken: {$regex: '\"SECURE_TOKEN\"[ ]*:[ ]*\"(.*?)\"'}\n" + + " $addGlobalParam:\n" + + " SomeVariable: {$xpath: 'root.abc'}"; + + Errors errors = new Errors(); + List<HttpFilter> filters = HttpFiltersConfigurator.getFilters(filterConfig, errors); + HttpFilterTestUtils.printErrors(errors); + + assertEquals(0, errors.getErrorCount()); + assertEquals(1, filters.size()); + assertTrue(filters.get(0) instanceof HttpResponseContentExtractorFilter); + + HttpResponseContentExtractorFilter filter = (HttpResponseContentExtractorFilter) filters.get(0); + + assertNotNull(filter.getPredicate()); + + List<Operation> operations = filter.getOperations(); + assertEquals(2, operations.size()); + assertTrue(operations.get(0) instanceof SetSessionParamOperation); + assertTrue(operations.get(1) instanceof SetGlobalParamOperation); + + SetSessionParamOperation op0 = (SetSessionParamOperation) operations.get(0); + assertEquals(true, op0.autocreate); + assertEquals(false, op0.checkValueExists); + assertEquals("SecureToken", op0.paramName); + assertTrue(op0.contentExtractor instanceof RegexValueExtractor); + + SetGlobalParamOperation op1 = (SetGlobalParamOperation) operations.get(1); + assertEquals(true, op1.checkValueExists); + assertEquals("SomeVariable", op1.paramName); + assertTrue(op1.contentExtractor instanceof XmlValueExtractor); + } + + private static class ConstContentExtractor implements ContentExtractor { + + private final String value; + + public ConstContentExtractor(String value) { + this.value = value; + } + + @Override + public String extract(String content) { + return value; + } + } +}
--- a/stress-tester/src/test/java/com/passus/st/client/http/filter/HttpScopeModificationFilterTest.java Thu Aug 10 14:03:21 2017 +0200 +++ b/stress-tester/src/test/java/com/passus/st/client/http/filter/HttpScopeModificationFilterTest.java Fri Aug 11 10:32:25 2017 +0200 @@ -28,6 +28,8 @@ public class HttpScopeModificationFilterTest { private final String sessionId = "sessionId"; + private final UnmutableValueExtractor oldValue = new UnmutableValueExtractor("paramValue"); + private final UnmutableValueExtractor newValue = new UnmutableValueExtractor("newParamValue"); @BeforeClass public static void beforeClass() { @@ -82,12 +84,12 @@ HttpRequest req = createRequest(); HttpScopeModificationFilter filter = new HttpScopeModificationFilter(); - filter.addOperation(new SetSessionParamOperation("paramName", new UnmutableValueExtractor("paramValue"), true)); + filter.addOperation(new SetSessionParamOperation("paramName", oldValue, true)); filter.filterOutbound(req, null, mockContext); assertEquals("paramValue", scopes.getSession(sessionId, false).get("paramName")); - filter.clearOperations(); - filter.addOperation(new SetSessionParamOperation("paramName", new UnmutableValueExtractor("newParamValue"), true)); + filter = new HttpScopeModificationFilter(); + filter.addOperation(new SetSessionParamOperation("paramName", newValue, true)); filter.filterOutbound(req, null, mockContext); assertEquals("paramValue", scopes.getSession(sessionId, false).get("paramName")); } @@ -99,12 +101,12 @@ HttpRequest req = createRequest(); HttpScopeModificationFilter filter = new HttpScopeModificationFilter(); - filter.addOperation(new SetSessionParamOperation("paramName", new UnmutableValueExtractor("paramValue"), false)); + filter.addOperation(new SetSessionParamOperation("paramName", oldValue, false)); filter.filterOutbound(req, null, mockContext); assertEquals("paramValue", scopes.getSession(sessionId, false).get("paramName")); - filter.clearOperations(); - filter.addOperation(new SetSessionParamOperation("paramName", new UnmutableValueExtractor("newParamValue"), false)); + filter = new HttpScopeModificationFilter(); + filter.addOperation(new SetSessionParamOperation("paramName", newValue, false)); filter.filterOutbound(req, null, mockContext); assertEquals("newParamValue", scopes.getSession(sessionId, false).get("paramName")); } @@ -131,12 +133,12 @@ HttpRequest req = createRequest(); HttpScopeModificationFilter filter = new HttpScopeModificationFilter(); - filter.addOperation(new SetGlobalParamOperation("paramName", new UnmutableValueExtractor("paramValue"), true)); + filter.addOperation(new SetGlobalParamOperation("paramName", oldValue, true)); filter.filterOutbound(req, null, mockContext); assertEquals("paramValue", scopes.getGlobal().get("paramName")); - filter.clearOperations(); - filter.addOperation(new SetSessionParamOperation("paramName", new UnmutableValueExtractor("newParamValue"), true)); + filter = new HttpScopeModificationFilter(); + filter.addOperation(new SetSessionParamOperation("paramName", newValue, true)); filter.filterOutbound(req, null, mockContext); assertEquals("paramValue", scopes.getGlobal().get("paramName")); } @@ -148,12 +150,12 @@ HttpRequest req = createRequest(); HttpScopeModificationFilter filter = new HttpScopeModificationFilter(); - filter.addOperation(new SetGlobalParamOperation("paramName", new UnmutableValueExtractor("paramValue"), false)); + filter.addOperation(new SetGlobalParamOperation("paramName", oldValue, false)); filter.filterOutbound(req, null, mockContext); assertEquals("paramValue", scopes.getGlobal().get("paramName")); - filter.clearOperations(); - filter.addOperation(new SetGlobalParamOperation("paramName", new UnmutableValueExtractor("newParamValue"), false)); + filter = new HttpScopeModificationFilter(); + filter.addOperation(new SetGlobalParamOperation("paramName", newValue, false)); filter.filterOutbound(req, null, mockContext); assertEquals("newParamValue", scopes.getGlobal().get("paramName")); }