diff --git a/neoload-project/src/main/java/com/neotys/neoload/model/v3/project/userpath/Page.java b/neoload-project/src/main/java/com/neotys/neoload/model/v3/project/userpath/Page.java new file mode 100644 index 00000000..e6415022 --- /dev/null +++ b/neoload-project/src/main/java/com/neotys/neoload/model/v3/project/userpath/Page.java @@ -0,0 +1,40 @@ +package com.neotys.neoload.model.v3.project.userpath; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.neotys.neoload.model.v3.project.SlaElement; +import com.neotys.neoload.model.v3.validation.constraints.RequiredCheck; +import com.neotys.neoload.model.v3.validation.groups.NeoLoad; +import org.immutables.value.Value; + +import javax.validation.constraints.Pattern; +import java.util.List; +import java.util.Optional; + +@Value.Immutable +@JsonSerialize(as = ImmutablePage.class) +@JsonDeserialize(as = ImmutablePage.class) +public interface Page extends Step, SlaElement { + List getChildren(); + + @Value.Default + @RequiredCheck(groups = {NeoLoad.class}) + default boolean isDynamic(){ + return false; + } + + @Value.Default + @RequiredCheck(groups = {NeoLoad.class}) + default String getName() { + return "#page#"; + } + + @Value.Default + @RequiredCheck(groups = {NeoLoad.class}) + default boolean isSequential(){ + return false; + } + + @Pattern(regexp = "(\\d+|\\$\\{\\w+\\})(-(\\d+|\\$\\{\\w+\\}))?", groups = {NeoLoad.class}) + Optional getThinkTime(); +} diff --git a/neoload-project/src/main/java/com/neotys/neoload/model/v3/project/userpath/Request.java b/neoload-project/src/main/java/com/neotys/neoload/model/v3/project/userpath/Request.java index bc942b42..b523e864 100644 --- a/neoload-project/src/main/java/com/neotys/neoload/model/v3/project/userpath/Request.java +++ b/neoload-project/src/main/java/com/neotys/neoload/model/v3/project/userpath/Request.java @@ -22,13 +22,14 @@ import com.neotys.neoload.model.v3.validation.groups.NeoLoad; @JsonInclude(value=Include.NON_DEFAULT) -@JsonPropertyOrder({Request.NAME, Request.URL, Request.SERVER, Request.METHOD, Request.HEADERS, Request.BODY, Request.EXTRACTORS, AssertionsElement.ASSERTIONS, Request.FOLLOW_REDIRECTS, SlaElement.SLA_PROFILE}) +@JsonPropertyOrder({Request.NAME, Request.URL, Request.SERVER, Request.METHOD, Request.HEADERS, Request.BODY, Request.EXTRACTORS, AssertionsElement.ASSERTIONS, Request.FOLLOW_REDIRECTS, SlaElement.SLA_PROFILE, Request.DYNAMIC_RESOURCES}) @JsonSerialize(as = ImmutableRequest.class) @JsonDeserialize(as = ImmutableRequest.class) @Value.Immutable @Value.Style(validationMethod = ValidationMethod.NONE) public interface Request extends Step, SlaElement, AssertionsElement { String NAME = "name"; + String DYNAMIC_RESOURCES = "dynamicResources"; String URL = "url"; String SERVER = "server"; String METHOD = "method"; @@ -65,6 +66,12 @@ public static Method of(final String name) { } } + @JsonProperty(DYNAMIC_RESOURCES) + @Value.Default + default boolean isDynamic(){ + return false; + } + @JsonProperty(NAME) @RequiredCheck(groups={NeoLoad.class}) @Value.Default diff --git a/neoload-project/src/main/resources/as-code.latest.schema.json b/neoload-project/src/main/resources/as-code.latest.schema.json index ff93006a..cbd14585 100644 --- a/neoload-project/src/main/resources/as-code.latest.schema.json +++ b/neoload-project/src/main/resources/as-code.latest.schema.json @@ -558,7 +558,8 @@ "delay": { "$ref": "#/definitions/user_paths/actions/delay" }, "think_time": { "$ref": "#/definitions/user_paths/actions/think_time" }, "javascript": { "$ref": "#/definitions/user_paths/actions/javascript" }, - "if": { "$ref": "#/definitions/user_paths/actions/if" } + "if": { "$ref": "#/definitions/user_paths/actions/if" }, + "page": { "$ref": "#/definitions/user_paths/actions/page" }, }, "additionalProperties": false } @@ -622,6 +623,7 @@ "additionalProperties": false } }, + "dynamic": { "$ref": "#/definitions/common/text" }, "sla_profile": { "$ref": "#/definitions/common/text" }, "body": { "$ref": "#/definitions/common/textblob" }, "extractors": { @@ -678,6 +680,18 @@ "then": { "$ref": "#/definitions/user_paths/container" }, "else": { "$ref": "#/definitions/user_paths/container" } } + }, + "page": { + "$id":"#/definitions/user_paths/actions/page", + "title":"Action: Page", + "type": "object", + "properties": { + "name": { "$ref": "#/definitions/common/text" }, + "description": { "$ref": "#/definitions/common/text" }, + "isDynamic": { "$ref": "#/definitions/common/text" }, + "isSequential": { "$ref": "#/definitions/common/text" }, + "thinkTime": { "$ref": "#/definitions/common/text" } + } } }, diff --git a/neoload-writer/src/main/java/com/neotys/neoload/model/v3/writers/neoload/WriterUtils.java b/neoload-writer/src/main/java/com/neotys/neoload/model/v3/writers/neoload/WriterUtils.java index b913ca16..8e2e500e 100644 --- a/neoload-writer/src/main/java/com/neotys/neoload/model/v3/writers/neoload/WriterUtils.java +++ b/neoload-writer/src/main/java/com/neotys/neoload/model/v3/writers/neoload/WriterUtils.java @@ -1,5 +1,6 @@ package com.neotys.neoload.model.v3.writers.neoload; +import com.google.common.annotations.VisibleForTesting; import com.neotys.neoload.model.v3.project.Element; import org.apache.commons.collections4.map.LazyMap; import org.slf4j.Logger; @@ -7,10 +8,7 @@ import org.w3c.dom.Document; import java.lang.reflect.Constructor; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.UUID; +import java.util.*; public class WriterUtils { @@ -78,4 +76,9 @@ public static boolean isNLVariable(final String value){ public static String extractVariableName(final String value) { return value.substring(NL_VARIABLE_START.length(), value.length()-NL_VARIABLE_END.length()); } + + @VisibleForTesting + public static Set> getGeneratedUids(){ + return elementUids.entrySet(); + } } diff --git a/neoload-writer/src/main/java/com/neotys/neoload/model/v3/writers/neoload/userpath/PageWriter.java b/neoload-writer/src/main/java/com/neotys/neoload/model/v3/writers/neoload/userpath/PageWriter.java new file mode 100644 index 00000000..58e4053d --- /dev/null +++ b/neoload-writer/src/main/java/com/neotys/neoload/model/v3/writers/neoload/userpath/PageWriter.java @@ -0,0 +1,60 @@ +package com.neotys.neoload.model.v3.writers.neoload.userpath; + +import com.neotys.neoload.model.v3.project.userpath.Page; +import com.neotys.neoload.model.v3.writers.neoload.ElementWriter; +import com.neotys.neoload.model.v3.writers.neoload.SlaElementWriter; +import com.neotys.neoload.model.v3.writers.neoload.WriterUtils; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class PageWriter extends ElementWriter { + + public static final String XML_TAG_NAME = "http-page"; + public static final String XML_ATTRIBUTE_THINK_TIME = "thinkTime"; + public static final String XML_ATTRIBUTE_THINK_TIME_START = "thinkTimeRangeStart"; + public static final String XML_ATTRIBUTE_THINK_TIME_STOP = "thinkTimeRangeEnd"; + public static final String XML_ATTRIBUTE_THINK_TIME_MODE = "thinkTimeMode"; + + public static final String MODE_RANGE_THINK_TIME = "MODE_RANGE_THINK_TIME"; + + public static final String XML_ATTRIBUTE_EXECUTE_RESOURCES_DYNAMICALLY = "executeResourcesDynamically"; + + private static Pattern patternThinkTime = Pattern.compile("(\\d+|\\$\\{\\w+\\})-(\\d+|\\$\\{\\w+\\})"); + + public PageWriter(final Page page) { + super(page); + } + + public static PageWriter of(final Page page){ + return new PageWriter(page); + } + + @Override + public void writeXML(final Document document, final Element currentElement, final String outputFolder) { + final Element xmlPage = document.createElement(XML_TAG_NAME); + super.writeXML(document, xmlPage, outputFolder); + final Page thePage = (Page) this.element; + thePage.getThinkTime().ifPresent(thinkTime -> writeDelay(xmlPage, thinkTime)); + xmlPage.setAttribute(XML_ATTRIBUTE_EXECUTE_RESOURCES_DYNAMICALLY, Boolean.toString(thePage.isDynamic())); + currentElement.appendChild(xmlPage); + SlaElementWriter.of(thePage).writeXML(xmlPage); + thePage.getChildren().forEach(pageElem -> { + WriterUtils.generateEmbeddedAction(document, xmlPage, pageElem); + WriterUtils.getWriterFor(pageElem).writeXML(document, currentElement, outputFolder); + }); + } + + private void writeDelay(final Element xmlPage, final String thinkTime) { + final Matcher matcher = patternThinkTime.matcher(thinkTime); + if(matcher.matches()){ + xmlPage.setAttribute(XML_ATTRIBUTE_THINK_TIME_MODE,MODE_RANGE_THINK_TIME); + xmlPage.setAttribute(XML_ATTRIBUTE_THINK_TIME_START, matcher.group(1)); + xmlPage.setAttribute(XML_ATTRIBUTE_THINK_TIME_STOP, matcher.group(2)); + }else{ + xmlPage.setAttribute(XML_ATTRIBUTE_THINK_TIME,thinkTime); + } + } +} diff --git a/neoload-writer/src/main/java/com/neotys/neoload/model/v3/writers/neoload/userpath/RequestWriter.java b/neoload-writer/src/main/java/com/neotys/neoload/model/v3/writers/neoload/userpath/RequestWriter.java index 95170cf2..382cef3f 100644 --- a/neoload-writer/src/main/java/com/neotys/neoload/model/v3/writers/neoload/userpath/RequestWriter.java +++ b/neoload-writer/src/main/java/com/neotys/neoload/model/v3/writers/neoload/userpath/RequestWriter.java @@ -4,13 +4,12 @@ import java.util.List; import java.util.Optional; +import com.neotys.neoload.model.v3.project.userpath.*; import org.w3c.dom.CDATASection; import org.w3c.dom.Document; import org.w3c.dom.Element; import com.google.common.net.MediaType; -import com.neotys.neoload.model.v3.project.userpath.Part; -import com.neotys.neoload.model.v3.project.userpath.Request; import com.neotys.neoload.model.v3.project.userpath.assertion.Assertion; import com.neotys.neoload.model.v3.util.Parameter; import com.neotys.neoload.model.v3.util.RequestUtils; @@ -49,8 +48,19 @@ public RequestWriter(Request request) { @Override public void writeXML(final Document document, final Element currentElement, final String outputFolder) { - final Element xmlRequest = document.createElement(XML_TAG_NAME); final Request theRequest = (Request) this.element; + if (theRequest.isDynamic()){ + final URL url = RequestUtils.parseUrl(Optional.ofNullable(theRequest.getUrl()).orElse("/")); + final Request requestUnDynamic = ImmutableRequest.copyOf(theRequest).withIsDynamic(false); + final ImmutablePage pageDynamic = ImmutablePage.builder() + .addChildren(requestUnDynamic) + .name(url.getPath()) + .isDynamic(true) + .build(); + PageWriter.of(pageDynamic).writeXML(document,currentElement,outputFolder); + return; + } + final Element xmlRequest = document.createElement(XML_TAG_NAME); super.writeXML(document, xmlRequest, outputFolder); fillXML(document, xmlRequest, theRequest); SlaElementWriter.of(theRequest).writeXML(xmlRequest); diff --git a/neoload-writer/src/main/java/com/neotys/neoload/model/v3/writers/neoload/userpath/ThinkTimeWriter.java b/neoload-writer/src/main/java/com/neotys/neoload/model/v3/writers/neoload/userpath/ThinkTimeWriter.java index a55f35da..01c216cc 100644 --- a/neoload-writer/src/main/java/com/neotys/neoload/model/v3/writers/neoload/userpath/ThinkTimeWriter.java +++ b/neoload-writer/src/main/java/com/neotys/neoload/model/v3/writers/neoload/userpath/ThinkTimeWriter.java @@ -1,30 +1,15 @@ package com.neotys.neoload.model.v3.writers.neoload.userpath; import com.neotys.neoload.model.v3.project.userpath.ThinkTime; -import com.neotys.neoload.model.v3.writers.neoload.ElementWriter; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -public class ThinkTimeWriter extends ElementWriter { - - public static final String XML_TAG_NAME = "delay-action"; - public static final String XML_DURATION_ATT = "duration"; - public static final String XML_ISTHINKTIME_ATT = "isThinkTime"; +public class ThinkTimeWriter extends AbstractDelayActionWriter { public ThinkTimeWriter(ThinkTime thinktime) { - super(thinktime); + super(thinktime,thinktime.getValue(),true); } public static ThinkTimeWriter of(final ThinkTime thinktime) { return new ThinkTimeWriter(thinktime); } - @Override - public void writeXML(final Document document, final Element currentElement, final String outputFolder) { - Element xmlDelay = document.createElement(XML_TAG_NAME); - super.writeXML(document, xmlDelay, outputFolder); - xmlDelay.setAttribute(XML_DURATION_ATT, ((ThinkTime)element).getValue()); - xmlDelay.setAttribute(XML_ISTHINKTIME_ATT, "true"); - currentElement.appendChild(xmlDelay); - } } diff --git a/neoload-writer/src/test/java/com/neotys/neoload/model/v3/writers/neoload/userpath/PageWriterTest.java b/neoload-writer/src/test/java/com/neotys/neoload/model/v3/writers/neoload/userpath/PageWriterTest.java new file mode 100644 index 00000000..4b3eace0 --- /dev/null +++ b/neoload-writer/src/test/java/com/neotys/neoload/model/v3/writers/neoload/userpath/PageWriterTest.java @@ -0,0 +1,105 @@ +package com.neotys.neoload.model.v3.writers.neoload.userpath; + +import com.google.common.io.Files; +import com.neotys.neoload.model.v3.project.userpath.ImmutablePage; +import com.neotys.neoload.model.v3.project.userpath.ImmutableRequest; +import com.neotys.neoload.model.v3.project.userpath.Page; +import com.neotys.neoload.model.v3.project.userpath.Request; +import com.neotys.neoload.model.v3.writers.neoload.WriterUtils; +import com.neotys.neoload.model.v3.writers.neoload.WrittingTestUtils; +import org.junit.Test; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xmlunit.assertj.XmlAssert; +import org.xmlunit.builder.Input; + +import javax.xml.parsers.ParserConfigurationException; + +public class PageWriterTest { + + @Test + public void writePageTestClassic() throws ParserConfigurationException { + final Document doc = WrittingTestUtils.generateEmptyDocument(); + final Element root = WrittingTestUtils.generateTestRootElement(doc); + final ImmutableRequest request = Request.builder().url("http://1.com").build(); + final Page page = ImmutablePage.builder() + .name("myPage") + .description("myDescription") + .isDynamic(true) + .addChildren(request) + .build(); + final String requestUid = WriterUtils.getElementUid(request); + final String expectedResult = + "" + + "" + + "myDescription" + + ""+ requestUid +"" + + "" + + "" + + ""; + PageWriter.of(page).writeXML(doc, root, Files.createTempDir().getAbsolutePath()); + + XmlAssert.assertThat(Input.fromDocument(doc)).and(Input.fromString(expectedResult)).areSimilar(); + } + + @Test + public void writePageTest() throws ParserConfigurationException { + final Document doc = WrittingTestUtils.generateEmptyDocument(); + final Element root = WrittingTestUtils.generateTestRootElement(doc); + final Request request1 = Request.builder().url("http://2.com").build(); + final Request request2 = Request.builder().url("http://3.com").build(); + final Page page = ImmutablePage.builder() + .name("myPage") + .description("myDescription") + .thinkTime("10-20") + .addChildren(request1) + .addChildren(request2) + .build(); + final String request1Uid = WriterUtils.getElementUid(request1); + final String request2Uid = WriterUtils.getElementUid(request2); + final String expectedResult = + "" + + "" + + "myDescription" + + ""+ request1Uid +"" + + ""+ request2Uid +"" + + "" + + "" + + "" + + ""; + PageWriter.of(page).writeXML(doc, root, Files.createTempDir().getAbsolutePath()); + + XmlAssert.assertThat(Input.fromDocument(doc)).and(Input.fromString(expectedResult)).areSimilar(); + } + + @Test + public void writePageSLATest() throws ParserConfigurationException { + final Document doc = WrittingTestUtils.generateEmptyDocument(); + final Element root = WrittingTestUtils.generateTestRootElement(doc); + final Request request1 = Request.builder().url("http://2.com").build(); + final Request request2 = Request.builder().url("http://3.com").build(); + final Page page = ImmutablePage.builder() + .name("myPage") + .description("myDescription") + .thinkTime("10-20") + .addChildren(request1) + .addChildren(request2) + .slaProfile("toto") + .build(); + final String request1Uid = WriterUtils.getElementUid(request1); + final String request2Uid = WriterUtils.getElementUid(request2); + final String expectedResult = + "" + + "" + + "myDescription" + + ""+ request1Uid +"" + + ""+ request2Uid +"" + + "" + + "" + + "" + + ""; + PageWriter.of(page).writeXML(doc, root, Files.createTempDir().getAbsolutePath()); + + XmlAssert.assertThat(Input.fromDocument(doc)).and(Input.fromString(expectedResult)).areSimilar(); + } +} diff --git a/neoload-writer/src/test/java/com/neotys/neoload/model/v3/writers/neoload/userpath/RequestWriterTest.java b/neoload-writer/src/test/java/com/neotys/neoload/model/v3/writers/neoload/userpath/RequestWriterTest.java index 66e141bf..e1973301 100644 --- a/neoload-writer/src/test/java/com/neotys/neoload/model/v3/writers/neoload/userpath/RequestWriterTest.java +++ b/neoload-writer/src/test/java/com/neotys/neoload/model/v3/writers/neoload/userpath/RequestWriterTest.java @@ -3,6 +3,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.io.Files; import com.neotys.neoload.model.v3.project.userpath.Header; +import com.neotys.neoload.model.v3.project.userpath.Page; import com.neotys.neoload.model.v3.project.userpath.Part; import com.neotys.neoload.model.v3.project.userpath.Request; import com.neotys.neoload.model.v3.writers.neoload.WriterUtils; @@ -14,6 +15,12 @@ import org.xmlunit.builder.Input; import javax.xml.parsers.ParserConfigurationException; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; public class RequestWriterTest { @@ -248,58 +255,41 @@ public void writeGetRequestWithAssertionsTest() throws ParserConfigurationExcept XmlAssert.assertThat(Input.fromDocument(doc)).and(Input.fromString(expectedResult)).areSimilar(); } - /*@Test - public void writePostSubmitFormRequestTest() throws ParserConfigurationException { - final Document doc = WrittingTestUtils.generateEmptyDocument(); - final Element root = WrittingTestUtils.generateTestRootElement(doc); - final String expectedResult = "" - + ""; - - (new RequestWriter(WrittingTestUtils.POST_SUBMIT_FORM_REQUEST_TEST)).writeXML(doc, root, Files.createTempDir().getAbsolutePath()); - - XmlAssert.assertThat(Input.fromDocument(doc)).and(Input.fromString(expectedResult)).areSimilar(); - } - @Test - public void writeRequestWithRecordedFiles() throws ParserConfigurationException, TransformerException, IOException { - - final String outputFolder = Files.createTempDir().getAbsolutePath(); - final Path recordedRequestsFolderPath = Paths.get(outputFolder, RECORDED_REQUESTS_FOLDER); - if (!recordedRequestsFolderPath.toFile().exists()) { - createDirectory(recordedRequestsFolderPath); - } - - final Path recordedResponsesFolderPath = Paths.get(outputFolder, RECORDED_RESPONSE_FOLDER); - if (!recordedResponsesFolderPath.toFile().exists()) { - createDirectory(recordedResponsesFolderPath); - } - - final Document doc = WrittingTestUtils.generateEmptyDocument(); - final Element root = WrittingTestUtils.generateTestRootElement(doc); - - (new RequestWriter(WrittingTestUtils.GET_REQUEST_WITH_RECORDED_FILES)).writeXML(doc, root, outputFolder); - - String generatedResult = WrittingTestUtils.getXmlString(doc); - Assertions.assertThat(generatedResult) - .contains("recorded-requests/req_requestBody") - .contains("HTTP/1.1 200 OK" + System.lineSeparator() + - "Date: Thu, 11 Feb 2015 13:23:40 GMT" + System.lineSeparator() + - "X-AspNet-Version: 2.0.50727" + System.lineSeparator() + - "Cache-Control: private, max-age=0" + System.lineSeparator() + - "Content-Type: application/json; charset=utf-8" + System.lineSeparator() + - "Content-Length: 150" + System.lineSeparator() + System.lineSeparator() + - "") - .contains("recorded-responses/res_responseBody_"); - }*/ + @Test + public void writeDynamicRequest() throws ParserConfigurationException { + Document doc = WrittingTestUtils.generateEmptyDocument(); + Element root = WrittingTestUtils.generateTestRootElement(doc); + + Request request = Request.builder() + .name("request_test") + .url("/test_path?param_name=param_value") + .server("server_test") + .method("GET") + .isDynamic(true) + .addHeaders(Header.builder().name("Content-Type").value("Text/Html").build()) + .build(); + + new RequestWriter(request).writeXML(doc, root, Files.createTempDir().getAbsolutePath()); + + final Set> generatedUids = WriterUtils.getGeneratedUids(); + assertEquals(2,generatedUids.size()); + final Optional pageId = generatedUids.stream().filter(c -> c.getKey() instanceof Page).map(Map.Entry::getValue).findAny(); + final Optional requestId = generatedUids.stream().filter(c -> c.getKey() instanceof Request).map(Map.Entry::getValue).findAny(); + assertTrue(pageId.isPresent()); + assertTrue(requestId.isPresent()); + String expectedResult = + "" + + "" + + ""+requestId.get()+"" + + "" + + "" + + "
" + + "" + + "" ; + + + XmlAssert.assertThat(Input.fromDocument(doc)).and(Input.fromString(expectedResult)).areSimilar(); + } } diff --git a/neoload-writer/src/test/java/com/neotys/neoload/model/v3/writers/neoload/userpath/ThinktimeWriterTest.java b/neoload-writer/src/test/java/com/neotys/neoload/model/v3/writers/neoload/userpath/ThinktimeWriterTest.java index 87fa481e..5de0c4b1 100644 --- a/neoload-writer/src/test/java/com/neotys/neoload/model/v3/writers/neoload/userpath/ThinktimeWriterTest.java +++ b/neoload-writer/src/test/java/com/neotys/neoload/model/v3/writers/neoload/userpath/ThinktimeWriterTest.java @@ -27,5 +27,19 @@ public void writeThinktimeXmlTest() throws ParserConfigurationException { XmlAssert.assertThat(Input.fromDocument(doc)).and(Input.fromString(expectedResult)).areSimilar(); } + @Test + public void writeThinktimeIntervalXmlTest() throws ParserConfigurationException { + final Document doc = WrittingTestUtils.generateEmptyDocument(); + final Element root = WrittingTestUtils.generateTestRootElement(doc); + final ThinkTime thinktime = new ThinkTime.Builder().name("myThinktime").value("1000-2000").description("myDescription").build(); + final String expectedResult = + "" + + "" + + "myDescription" + + "" + + ""; + ThinkTimeWriter.of(thinktime).writeXML(doc, root, Files.createTempDir().getAbsolutePath()); + XmlAssert.assertThat(Input.fromDocument(doc)).and(Input.fromString(expectedResult)).areSimilar(); + } }