/* * Copyright 2017 ThoughtWorks, Inc. * * 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.thoughtworks.go.server.service; import com.googlecode.junit.ext.RunIf; import com.thoughtworks.go.config.CruiseConfig; import com.thoughtworks.go.config.GoConfigDao; import com.thoughtworks.go.config.PipelineConfig; import com.thoughtworks.go.config.materials.ScmMaterial; import com.thoughtworks.go.config.materials.dependency.DependencyMaterial; import com.thoughtworks.go.config.materials.mercurial.HgMaterial; import com.thoughtworks.go.domain.valuestreammap.Node; import com.thoughtworks.go.helper.MaterialsMother; import com.thoughtworks.go.helpers.GraphGenerator; import com.thoughtworks.go.junitext.DatabaseChecker; import com.thoughtworks.go.junitext.GoJUnitExtSpringRunner; import com.thoughtworks.go.server.dao.DatabaseAccessHelper; import com.thoughtworks.go.server.domain.Username; import com.thoughtworks.go.server.persistence.MaterialRepository; import com.thoughtworks.go.server.presentation.models.ValueStreamMapPresentationModel; import com.thoughtworks.go.server.service.result.DefaultLocalizedOperationResult; import com.thoughtworks.go.server.service.result.HttpLocalizedOperationResult; import com.thoughtworks.go.server.transaction.TransactionTemplate; import com.thoughtworks.go.util.GoConfigFileHelper; import org.hamcrest.Matchers; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import java.util.ArrayList; import java.util.List; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertThat; @RunWith(GoJUnitExtSpringRunner.class) @ContextConfiguration(locations = { "classpath:WEB-INF/applicationContext-global.xml", "classpath:WEB-INF/applicationContext-dataLocalAccess.xml", "classpath:WEB-INF/applicationContext-acegi-security.xml" }) public class ValueStreamMapPerformanceTest { @Autowired private GoConfigDao goConfigDao; @Autowired private GoConfigService goConfigService; @Autowired private DatabaseAccessHelper dbHelper; @Autowired private ValueStreamMapService valueStreamMapService; @Autowired private MaterialRepository materialRepository; @Autowired private TransactionTemplate transactionTemplate; private GoConfigFileHelper configHelper; private ScheduleTestUtil u; private GraphGenerator graphGenerator; @Before public void setup() throws Exception { configHelper = new GoConfigFileHelper(); dbHelper.onSetUp(); configHelper.usingCruiseConfigDao(goConfigDao).initializeConfigFile(); configHelper.onSetUp(); goConfigService.forceNotifyListeners(); u = new ScheduleTestUtil(transactionTemplate, materialRepository, dbHelper, configHelper); graphGenerator = new GraphGenerator(configHelper, u); } @After public void tearDown() throws Exception { configHelper.onTearDown(); dbHelper.onTearDown(); } @Test public void shouldTestVSMForNPipelines() throws Exception { final int numberOfDownstreamPipelines = 5; final CruiseConfig cruiseConfig = setupVSM(numberOfDownstreamPipelines); ArrayList<Thread> ts = new ArrayList<>(); int numberOfParallelRequests = 10; for (int i = 0; i < numberOfParallelRequests; i++) { final int finalI = i; Thread t = new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(5000); doRun(numberOfDownstreamPipelines, cruiseConfig, "Thread" + finalI); } catch (InterruptedException e) { e.printStackTrace(); } } }, "Thread" + i); ts.add(t); } for (Thread t : ts) { t.start(); } for (Thread t : ts) { t.join(); } } @Test(timeout = 240000) @RunIf(value = DatabaseChecker.class, arguments = {DatabaseChecker.H2}) public void shouldTestVSMForMeshInUpstreamAndDownstream() throws Exception { int numberOfNodesPerLevel = 5; int numberOfLevels = 5; int numberOfInstancesForUpstream = 1; int numberOfInstancesForDownstream = 10; ScmMaterial svn = u.wf((ScmMaterial) MaterialsMother.defaultMaterials().get(0), "folder1"); String[] svn_revs = {"svn_1"}; u.checkinInOrder(svn, svn_revs); PipelineConfig upstreamConfig = graphGenerator.createPipelineWithInstances("upstream", new ArrayList<>(), 1); PipelineConfig currentConfig = graphGenerator.createMesh(upstreamConfig, "current", "up", numberOfInstancesForUpstream, numberOfNodesPerLevel, numberOfLevels); graphGenerator.createMesh(currentConfig, "downstream", "down", numberOfInstancesForDownstream, numberOfNodesPerLevel, numberOfLevels); long start = System.currentTimeMillis(); DefaultLocalizedOperationResult result = new DefaultLocalizedOperationResult(); ValueStreamMapPresentationModel presentationModel = valueStreamMapService.getValueStreamMap("current", 1, Username.ANONYMOUS, result); long timeTaken = (System.currentTimeMillis() - start) / 1000; assertThat(String.format("VSM took %ds. Should have been generated in 30s.", timeTaken), timeTaken, Matchers.lessThan(30l)); assertThat(result.isSuccessful(), is(true)); assertThat(presentationModel.getNodesAtEachLevel().size(), is(14)); } private void doRun(int numberOfDownstreamPipelines, CruiseConfig cruiseConfig, String threadName) throws InterruptedException { HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); for (PipelineConfig pipelineConfig : cruiseConfig.allPipelines()) { ValueStreamMapPresentationModel map = valueStreamMapService.getValueStreamMap(pipelineConfig.name().toString(), 1, Username.ANONYMOUS, result); assertThat(getAllNodes(map).size(), is(numberOfDownstreamPipelines + 2)); } } private List<Node> getAllNodes(ValueStreamMapPresentationModel presentationModel) { ArrayList<Node> nodes = new ArrayList<>(); List<List<Node>> nodesAtEachLevel = presentationModel.getNodesAtEachLevel(); for (List<Node> nodesAtLevel : nodesAtEachLevel) { nodes.addAll(nodesAtLevel); } return nodes; } private CruiseConfig setupVSM(int numberOfDownstreamPipelines) { HgMaterial hg = new HgMaterial("hgurl", "folder"); String hg_revs = "hg1"; u.checkinInOrder(hg, hg_revs); ScheduleTestUtil.AddedPipeline up = u.saveConfigWith("u", new ScheduleTestUtil.MaterialDeclaration(hg, "dest")); String up_r = u.runAndPass(up, hg_revs); ScheduleTestUtil.AddedPipeline previouslyCreatedPipeline = up; String previousRun = up_r; for (int i = 0; i < numberOfDownstreamPipelines; i++) { DependencyMaterial dep = new DependencyMaterial(previouslyCreatedPipeline.config.name(), previouslyCreatedPipeline.config.get(0).name()); ScheduleTestUtil.AddedPipeline d = u.saveConfigWith("d" + i, new ScheduleTestUtil.MaterialDeclaration(dep, "random")); String currentRun = u.runAndPass(d, previousRun); previouslyCreatedPipeline = d; previousRun = currentRun; } return goConfigDao.load(); } }