diff options
author | Denis Anisimov <denis@vaadin.com> | 2016-10-14 11:36:18 +0300 |
---|---|---|
committer | Denis Anisimov <denis@vaadin.com> | 2016-10-14 14:26:01 +0000 |
commit | 3b454d94ae64f743d05cd7e94d00b354ff9d14eb (patch) | |
tree | b1dffb9ceb9818d292af4a1fda06bf05e5eeb74a | |
parent | ff4d7b1e9b7b4bf9a15bd199acc3d7a12c519cc2 (diff) | |
download | vaadin-framework-3b454d94ae64f743d05cd7e94d00b354ff9d14eb.tar.gz vaadin-framework-3b454d94ae64f743d05cd7e94d00b354ff9d14eb.zip |
Memory measurement test for V7&V8 Grids, 1 item and 100 000 items.
Change-Id: I66b358ff40703f2713272323ba1c5ae8778c8413
7 files changed, 325 insertions, 8 deletions
@@ -680,6 +680,15 @@ </plugins> </build> </profile> + <profile> + <id>measurements</id> + <activation> + <activeByDefault>false</activeByDefault> + </activation> + <properties> + <skipTests>true</skipTests> + </properties> + </profile> </profiles> </project> diff --git a/uitest/pom.xml b/uitest/pom.xml index 6055d84d97..4b183e578b 100644 --- a/uitest/pom.xml +++ b/uitest/pom.xml @@ -330,6 +330,97 @@ <skip.uitest.deployment>false</skip.uitest.deployment> </properties> </profile> + <profile> + <id>default</id> + <activation> + <activeByDefault>true</activeByDefault> + </activation> + <build> + <plugins> + <plugin> + <artifactId>maven-surefire-plugin</artifactId> + <configuration> + <excludedGroups>com.vaadin.testcategory.MeasurementTest</excludedGroups> + </configuration> + </plugin> + </plugins> + </build> + </profile> + <profile> + <id>measurements</id> + <activation> + <activeByDefault>false</activeByDefault> + </activation> + <properties> + <skipTests>false</skipTests> + </properties> + <build> + <plugins> + <plugin> + <artifactId>maven-failsafe-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>integration-test</goal> + <goal>verify</goal> + </goals> + </execution> + </executions> + <configuration> + <groups>com.vaadin.testcategory.MeasurementTest</groups> + <systemPropertyVariables> + <phantomjs.binary.path>${phantomjs.binary}</phantomjs.binary.path> + </systemPropertyVariables> + </configuration> + </plugin> + <plugin> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-maven-plugin</artifactId> + <configuration> + <httpConnector> + <port>8888</port> + </httpConnector> + <scanIntervalSeconds>-1</scanIntervalSeconds> + <stopPort>8081</stopPort> + <stopWait>5</stopWait> + <stopKey>foo</stopKey> + </configuration> + <executions> + <!-- start and stop jetty (running our app) when + running integration tests --> + <execution> + <id>start-jetty</id> + <phase>pre-integration-test</phase> + <goals> + <goal>start</goal> + </goals> + </execution> + <execution> + <id>stop-jetty</id> + <phase>post-integration-test</phase> + <goals> + <goal>stop</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <groupId>com.github.klieber</groupId> + <artifactId>phantomjs-maven-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>install</goal> + </goals> + <configuration> + <version>${phantomjs.version}</version> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> </profiles> </project> diff --git a/uitest/src/main/java/com/vaadin/testcategory/MeasurementTest.java b/uitest/src/main/java/com/vaadin/testcategory/MeasurementTest.java new file mode 100644 index 0000000000..798686776f --- /dev/null +++ b/uitest/src/main/java/com/vaadin/testcategory/MeasurementTest.java @@ -0,0 +1,30 @@ +/* + * Copyright 2000-2016 Vaadin Ltd. + * + * 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.vaadin.testcategory; + +/** + * Test that is not supposed to be run on validation and run without other + * verification tests. + * <p> + * The purpose of the test to make some measurement (memory, time, etc.). + * + * + * @author Vaadin Ltd + * + */ +public interface MeasurementTest { + +} diff --git a/uitest/src/main/java/com/vaadin/tests/performance/AbstractBeansMemoryTest.java b/uitest/src/main/java/com/vaadin/tests/performance/AbstractBeansMemoryTest.java index 62b42f56f8..526b758e22 100644 --- a/uitest/src/main/java/com/vaadin/tests/performance/AbstractBeansMemoryTest.java +++ b/uitest/src/main/java/com/vaadin/tests/performance/AbstractBeansMemoryTest.java @@ -15,6 +15,7 @@ */ package com.vaadin.tests.performance; +import java.lang.reflect.Field; import java.math.BigDecimal; import java.util.Collections; import java.util.Date; @@ -24,34 +25,65 @@ import java.util.stream.Collectors; import java.util.stream.IntStream; import com.vaadin.server.VaadinRequest; -import com.vaadin.tests.components.AbstractTestUI; import com.vaadin.tests.data.bean.Address; import com.vaadin.tests.data.bean.Country; import com.vaadin.tests.data.bean.Person; import com.vaadin.tests.data.bean.Sex; import com.vaadin.ui.AbstractComponent; +import com.vaadin.ui.Button; import com.vaadin.ui.Component; +import com.vaadin.ui.HasComponents; +import com.vaadin.ui.Label; import com.vaadin.ui.MenuBar; import com.vaadin.ui.MenuBar.MenuItem; +import com.vaadin.ui.UI; +import com.vaadin.ui.VerticalLayout; + +import jdk.nashorn.internal.ir.debug.ObjectSizeCalculator; /** * @author Vaadin Ltd * */ public abstract class AbstractBeansMemoryTest<T extends AbstractComponent> - extends AbstractTestUI { + extends UI { private int dataSize; private boolean isInMemory; private boolean isDataOnly; + private Label logLabel; + private Label memoryLabel; + @Override - protected void setup(VaadinRequest request) { + protected void init(VaadinRequest request) { + String items = request.getParameter("items"); + int itemsCount = 1; + if (items != null) { + itemsCount = Integer.parseInt(items); + } + + VerticalLayout layout = new VerticalLayout(); + setContent(layout); + layout.addComponent(new Label(getClass().getSimpleName())); + + memoryLabel = new Label(); + memoryLabel.setId("memory"); + layout.addComponent(memoryLabel); + + logLabel = new Label(); + logLabel.setId("log"); + layout.addComponent(logLabel); + T component = createComponent(); - setData(null, 1000000, component, true); - addComponent(createMenu(component)); + setData(null, itemsCount, component, true); + layout.addComponent(createMenu(component)); - addComponent(component); + layout.addComponent(component); + + Button close = new Button("Close UI", event -> close()); + close.setId("close"); + layout.addComponent(close); } protected abstract T createComponent(); @@ -92,12 +124,19 @@ public abstract class AbstractBeansMemoryTest<T extends AbstractComponent> protected abstract void setBackendContainer(T component, List<Person> data); + @Override + public VerticalLayout getContent() { + return (VerticalLayout) super.getContent(); + } + + @SuppressWarnings("restriction") private void setData(MenuItem item, int size, T component, boolean memoryContainer) { if (item != null) { MenuItem parent = item.getParent(); parent.getChildren().stream().filter(itm -> !itm.equals(item)) .forEach(itm -> itm.setChecked(false)); + logLabel.setValue(item.getText()); } dataSize = size; isInMemory = memoryContainer; @@ -113,6 +152,24 @@ public abstract class AbstractBeansMemoryTest<T extends AbstractComponent> } else { setBackendContainer(component, persons); } + + HasComponents container = component.getParent(); + setParent(component, null); + memoryLabel.setValue( + String.valueOf(ObjectSizeCalculator.getObjectSize(component))); + + setParent(component, container); + } + + private void setParent(Component component, Component parent) { + try { + Field field = AbstractComponent.class.getDeclaredField("parent"); + field.setAccessible(true); + field.set(component, parent); + } catch (NoSuchFieldException | SecurityException + | IllegalArgumentException | IllegalAccessException e) { + throw new RuntimeException(e); + } } private Component createMenu(T component) { @@ -141,10 +198,12 @@ public abstract class AbstractBeansMemoryTest<T extends AbstractComponent> } private void createContainerSizeMenu(MenuItem menu, T component) { - List<MenuItem> items = IntStream.of(1, 100000, 500000, 1000000) + List<MenuItem> items = IntStream.of(1, 10000, 100000, 500000, 1000000) .mapToObj(size -> addContainerSizeMenu(size, menu, component)) .collect(Collectors.toList()); - items.get(items.size() - 1).setChecked(true); + if (dataSize == 1) { + items.get(0).setChecked(true); + } } private MenuItem addContainerSizeMenu(int size, MenuItem menu, diff --git a/uitest/src/main/java/com/vaadin/tests/performance/CompatibilityGridMemory.java b/uitest/src/main/java/com/vaadin/tests/performance/CompatibilityGridMemory.java index f2dcdd6851..291da9065d 100644 --- a/uitest/src/main/java/com/vaadin/tests/performance/CompatibilityGridMemory.java +++ b/uitest/src/main/java/com/vaadin/tests/performance/CompatibilityGridMemory.java @@ -19,6 +19,10 @@ import java.util.List; import java.util.Optional; import java.util.function.Function; +import javax.servlet.annotation.WebServlet; + +import com.vaadin.annotations.VaadinServletConfiguration; +import com.vaadin.server.VaadinServlet; import com.vaadin.tests.data.bean.Address; import com.vaadin.tests.data.bean.Person; import com.vaadin.v7.data.Item; @@ -33,6 +37,17 @@ import com.vaadin.v7.ui.Grid; */ public class CompatibilityGridMemory extends AbstractBeansMemoryTest<Grid> { + public static final String PATH = "/grid-compatibility-memory/"; + + /** + * The main servlet for the application. + */ + @WebServlet(urlPatterns = PATH + + "*", name = "CompatibilityGridServlet", asyncSupported = true) + @VaadinServletConfiguration(ui = CompatibilityGridMemory.class, productionMode = false, widgetset = "com.vaadin.v7.Vaadin7WidgetSet") + public static class Servlet extends VaadinServlet { + } + private static class ColumnGenerator extends PropertyValueGenerator<String> { diff --git a/uitest/src/main/java/com/vaadin/tests/performance/GridMemory.java b/uitest/src/main/java/com/vaadin/tests/performance/GridMemory.java index 10f5be93ec..079bfb555d 100644 --- a/uitest/src/main/java/com/vaadin/tests/performance/GridMemory.java +++ b/uitest/src/main/java/com/vaadin/tests/performance/GridMemory.java @@ -18,6 +18,10 @@ package com.vaadin.tests.performance; import java.util.List; import java.util.Optional; +import javax.servlet.annotation.WebServlet; + +import com.vaadin.annotations.VaadinServletConfiguration; +import com.vaadin.server.VaadinServlet; import com.vaadin.tests.data.bean.Address; import com.vaadin.tests.data.bean.Person; import com.vaadin.ui.Grid; @@ -28,6 +32,17 @@ import com.vaadin.ui.Grid; */ public class GridMemory extends AbstractBeansMemoryTest<Grid<Person>> { + public static final String PATH = "/grid-memory/"; + + /** + * The main servlet for the application. + */ + @WebServlet(urlPatterns = PATH + + "*", name = "GridServlet", asyncSupported = true) + @VaadinServletConfiguration(ui = GridMemory.class, productionMode = false) + public static class Servlet extends VaadinServlet { + } + @Override protected Grid<Person> createComponent() { Grid<Person> grid = new Grid<>(); diff --git a/uitest/src/test/java/com/vaadin/tests/performance/MemoryIT.java b/uitest/src/test/java/com/vaadin/tests/performance/MemoryIT.java new file mode 100644 index 0000000000..b5ba723c7d --- /dev/null +++ b/uitest/src/test/java/com/vaadin/tests/performance/MemoryIT.java @@ -0,0 +1,98 @@ +/* + * Copyright 2000-2016 Vaadin Ltd. + * + * 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.vaadin.tests.performance; + +import org.apache.commons.lang3.StringUtils; +import org.junit.Assert; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import com.vaadin.testbench.By; +import com.vaadin.testcategory.MeasurementTest; +import com.vaadin.tests.tb3.SingleBrowserTest; + +@Category(MeasurementTest.class) +public class MemoryIT extends SingleBrowserTest { + + @Test + public void measureMemory() { + printTeamcityStats("grid-v8-one-item-size", + getGridSize(GridMemory.PATH, 1)); + printTeamcityStats("grid-v7-one-item-size", + getGridSize(CompatibilityGridMemory.PATH, 1)); + + printTeamcityStats("grid-v8-100thousand-items-size", + getGridSize(GridMemory.PATH, 100000)); + printTeamcityStats("grid-v7-100thousand-items-size", + getGridSize(CompatibilityGridMemory.PATH, 100000)); + } + + @Override + protected void closeApplication() { + } + + @Override + protected String getScreenshotDirectory() { + return "."; + } + + private long getGridSize(String path, int itemsCount) { + // Repeat until we get consecutive results within 0.1% of each other + double lastResult = 0; + int stableNumber = 0; + for (int i = 0; i < 500; i++) { + openUI(path, itemsCount); + long currentResult = Long + .parseLong(findElement(By.id("memory")).getText()); + close(); + + if (approx(lastResult, currentResult, 0.001)) { + stableNumber++; + } + lastResult = currentResult; + if (stableNumber == 5) { + return currentResult; + } + } + + Assert.fail("Memory size does not stabilize"); + return -1; + } + + private boolean approx(double num1, double num2, double epsilon) { + double delta = Math.abs(num1 - num2); + double deltaLimit = num2 * epsilon; + return delta < deltaLimit; + } + + private void openUI(String path, int itemsNumber) { + getDriver().get(StringUtils.strip(getBaseURL(), "/") + path + "?items=" + + itemsNumber); + Assert.assertTrue(isElementPresent(By.className("v-grid"))); + } + + private void close() { + findElement(By.id("close")).click(); + } + + private void printTeamcityStats(String key, long value) { + // ##teamcity[buildStatisticValue key='<valueTypeKey>' + // value='<value>'] + System.out.println("##teamcity[buildStatisticValue key='" + key + + "' value='" + value + "']"); + + } +} |