PageRenderTime 44ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/src/test/java/hudson/matrix/MatrixProjectTest.java

https://gitlab.com/vectorci/matrix-project-plugin
Java | 687 lines | 476 code | 107 blank | 104 comment | 23 complexity | 5c1b73c4b89679bf0f4f755b51d0641a MD5 | raw file
  1. /*
  2. * The MIT License
  3. *
  4. * Copyright (c) 2004-2011, Sun Microsystems, Inc., CloudBees, Inc.
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. */
  24. package hudson.matrix;
  25. import com.gargoylesoftware.htmlunit.html.HtmlPage;
  26. import hudson.cli.CLICommandInvoker;
  27. import hudson.cli.DeleteBuildsCommand;
  28. import hudson.model.Cause;
  29. import hudson.model.Result;
  30. import hudson.slaves.DumbSlave;
  31. import hudson.slaves.RetentionStrategy;
  32. import hudson.tasks.Ant;
  33. import hudson.tasks.ArtifactArchiver;
  34. import hudson.tasks.Fingerprinter;
  35. import hudson.tasks.LogRotator;
  36. import hudson.tasks.Maven;
  37. import hudson.tasks.Shell;
  38. import hudson.tasks.BatchFile;
  39. import org.jvnet.hudson.test.Email;
  40. import org.jvnet.hudson.test.SingleFileSCM;
  41. import org.jvnet.hudson.test.UnstableBuilder;
  42. import org.jvnet.hudson.test.recipes.LocalData;
  43. import com.gargoylesoftware.htmlunit.html.HtmlTable;
  44. import com.gargoylesoftware.htmlunit.html.HtmlTableCell;
  45. import com.gargoylesoftware.htmlunit.html.HtmlTableRow;
  46. import hudson.FilePath;
  47. import org.jvnet.hudson.test.Issue;
  48. import org.jvnet.hudson.test.TestBuilder;
  49. import hudson.model.AbstractBuild;
  50. import hudson.Launcher;
  51. import hudson.model.BuildListener;
  52. import hudson.util.OneShotEvent;
  53. import java.io.IOException;
  54. import java.util.concurrent.Future;
  55. import java.util.concurrent.TimeUnit;
  56. import java.util.concurrent.TimeoutException;
  57. import hudson.model.JDK;
  58. import hudson.model.Slave;
  59. import hudson.Functions;
  60. import hudson.model.ParametersDefinitionProperty;
  61. import hudson.model.FileParameterDefinition;
  62. import hudson.model.Cause.LegacyCodeCause;
  63. import hudson.model.ParametersAction;
  64. import hudson.model.FileParameterValue;
  65. import hudson.model.StringParameterDefinition;
  66. import hudson.model.StringParameterValue;
  67. import java.util.List;
  68. import java.util.ArrayList;
  69. import java.util.concurrent.CountDownLatch;
  70. import static hudson.model.Node.Mode.EXCLUSIVE;
  71. import hudson.model.ParameterDefinition;
  72. import hudson.model.ParameterValue;
  73. import hudson.model.queue.QueueTaskFuture;
  74. import java.io.File;
  75. import java.lang.reflect.Method;
  76. import java.util.Arrays;
  77. import java.util.Collections;
  78. import java.util.HashMap;
  79. import java.util.HashSet;
  80. import java.util.Map;
  81. import java.util.Set;
  82. import jenkins.model.Jenkins;
  83. import static org.junit.Assert.*;
  84. import org.junit.Rule;
  85. import org.junit.Test;
  86. import org.jvnet.hudson.test.JenkinsRule;
  87. import org.jvnet.hudson.test.RandomlyFails;
  88. import org.junit.rules.TemporaryFolder;
  89. /**
  90. *
  91. *
  92. * @author Kohsuke Kawaguchi
  93. */
  94. public class MatrixProjectTest {
  95. @Rule public JenkinsRule j = new JenkinsRule();
  96. @Rule public TemporaryFolder tmp = new TemporaryFolder();
  97. /**
  98. * Tests that axes are available as build variables in the Ant builds.
  99. */
  100. @Test
  101. public void testBuildAxisInAnt() throws Exception {
  102. MatrixProject p = createMatrixProject();
  103. Ant.AntInstallation ant = j.configureDefaultAnt();
  104. p.getBuildersList().add(new Ant("-Dprop=${db} test", ant.getName(), null, null, null));
  105. // we need a dummy build script that echos back our property
  106. p.setScm(new SingleFileSCM("build.xml", "<project default='test'><target name='test'><echo>assertion ${prop}=${db}</echo></target></project>"));
  107. MatrixBuild build = p.scheduleBuild2(0, new Cause.UserCause()).get();
  108. List<MatrixRun> runs = build.getRuns();
  109. assertEquals(4,runs.size());
  110. for (MatrixRun run : runs) {
  111. j.assertBuildStatus(Result.SUCCESS, run);
  112. String expectedDb = run.getParent().getCombination().get("db");
  113. j.assertLogContains("assertion "+expectedDb+"="+expectedDb, run);
  114. }
  115. }
  116. /**
  117. * Tests that axes are available as build variables in the Maven builds.
  118. */
  119. @Test
  120. public void testBuildAxisInMaven() throws Exception {
  121. MatrixProject p = createMatrixProject();
  122. Maven.MavenInstallation maven = j.configureDefaultMaven();
  123. p.getBuildersList().add(new Maven("-Dprop=${db} validate", maven.getName()));
  124. // we need a dummy build script that echos back our property
  125. p.setScm(new SingleFileSCM("pom.xml",getClass().getResource("echo-property.pom")));
  126. MatrixBuild build = p.scheduleBuild2(0).get();
  127. List<MatrixRun> runs = build.getRuns();
  128. assertEquals(4,runs.size());
  129. for (MatrixRun run : runs) {
  130. j.assertBuildStatus(Result.SUCCESS, run);
  131. String expectedDb = run.getParent().getCombination().get("db");
  132. System.out.println(run.getLog());
  133. j.assertLogContains("assertion "+expectedDb+"="+expectedDb, run);
  134. // also make sure that the variables are expanded at the command line level.
  135. assertFalse(run.getLog().contains("-Dprop=${db}"));
  136. }
  137. }
  138. /**
  139. * Test that configuration filters work
  140. */
  141. @Test
  142. public void testConfigurationFilter() throws Exception {
  143. MatrixProject p = createMatrixProject();
  144. p.setCombinationFilter("db==\"mysql\"");
  145. MatrixBuild build = p.scheduleBuild2(0).get();
  146. assertEquals(2, build.getRuns().size());
  147. }
  148. /**
  149. * Test that touch stone builds work
  150. */
  151. @Test
  152. public void testTouchStone() throws Exception {
  153. MatrixProject p = createMatrixProject();
  154. p.setTouchStoneCombinationFilter("db==\"mysql\"");
  155. p.setTouchStoneResultCondition(Result.SUCCESS);
  156. MatrixBuild build = p.scheduleBuild2(0).get();
  157. assertEquals(4, build.getRuns().size());
  158. p.getBuildersList().add(new UnstableBuilder());
  159. build = p.scheduleBuild2(0).get();
  160. assertEquals(2, build.getExactRuns().size());
  161. }
  162. protected MatrixProject createMatrixProject() throws IOException {
  163. MatrixProject p = j.createMatrixProject();
  164. // set up 2x2 matrix
  165. AxisList axes = new AxisList();
  166. axes.add(new TextAxis("db","mysql","oracle"));
  167. axes.add(new TextAxis("direction","north","south"));
  168. p.setAxes(axes);
  169. return p;
  170. }
  171. /**
  172. * Fingerprinter failed to work on the matrix project.
  173. */
  174. @Email("http://www.nabble.com/1.286-version-and-fingerprints-option-broken-.-td22236618.html")
  175. @Test
  176. public void testFingerprinting() throws Exception {
  177. MatrixProject p = createMatrixProject();
  178. if (Functions.isWindows())
  179. p.getBuildersList().add(new BatchFile("echo \"\" > p"));
  180. else
  181. p.getBuildersList().add(new Shell("touch p"));
  182. p.getPublishersList().add(new ArtifactArchiver("p",null,false, false));
  183. p.getPublishersList().add(new Fingerprinter("",true));
  184. j.buildAndAssertSuccess(p);
  185. }
  186. void assertRectangleTable(MatrixProject p) throws Exception {
  187. HtmlPage html = j.createWebClient().getPage(p);
  188. HtmlTable table = html.selectSingleNode("id('matrix')/table");
  189. // remember cells that are extended from rows above.
  190. Map<Integer,Integer> rowSpans = new HashMap<Integer,Integer>();
  191. Integer masterWidth = null;
  192. for (HtmlTableRow r : table.getRows()) {
  193. int width = 0;
  194. for (HtmlTableCell c : r.getCells()) {
  195. width += c.getColumnSpan();
  196. }
  197. for (Integer val : rowSpans.values()) {
  198. width += val;
  199. }
  200. if (masterWidth == null) {
  201. masterWidth = width;
  202. } else {
  203. assertEquals(masterWidth.intValue(), width);
  204. }
  205. for (HtmlTableCell c : r.getCells()) {
  206. int rowSpan = c.getRowSpan();
  207. Integer val = rowSpans.get(rowSpan);
  208. rowSpans.put(rowSpan, (val != null ? val : 0) + c.getColumnSpan());
  209. }
  210. // shift rowSpans by one
  211. Map<Integer,Integer> nrs = new HashMap<Integer,Integer>();
  212. for (Map.Entry<Integer,Integer> entry : rowSpans.entrySet()) {
  213. if (entry.getKey() > 1) {
  214. nrs.put(entry.getKey() - 1, entry.getValue());
  215. }
  216. }
  217. rowSpans = nrs;
  218. }
  219. }
  220. @Issue("JENKINS-4245")
  221. @Test
  222. public void testLayout1() throws Exception {
  223. // 5*5*5*5*5 matrix
  224. MatrixProject p = createMatrixProject();
  225. List<Axis> axes = new ArrayList<Axis>();
  226. for (String name : new String[] {"a", "b", "c", "d", "e"}) {
  227. axes.add(new TextAxis(name, "1", "2", "3", "4"));
  228. }
  229. p.setAxes(new AxisList(axes));
  230. assertRectangleTable(p);
  231. }
  232. @Issue("JENKINS-4245")
  233. @Test
  234. public void testLayout2() throws Exception {
  235. // 2*3*4*5*6 matrix
  236. MatrixProject p = createMatrixProject();
  237. List<Axis> axes = new ArrayList<Axis>();
  238. for (int i = 2; i <= 6; i++) {
  239. List<String> vals = new ArrayList<String>();
  240. for (int j = 1; j <= i; j++) {
  241. vals.add(Integer.toString(j));
  242. }
  243. axes.add(new TextAxis("axis" + i, vals));
  244. }
  245. p.setAxes(new AxisList(axes));
  246. assertRectangleTable(p);
  247. }
  248. /**
  249. * Makes sure that the configuration correctly roundtrips.
  250. */
  251. @Test
  252. public void testConfigRoundtrip() throws Exception {
  253. j.jenkins.getJDKs().addAll(Arrays.asList(
  254. new JDK("jdk1.7","somewhere"),
  255. new JDK("jdk1.6","here"),
  256. new JDK("jdk1.5","there")));
  257. Slave[] slaves = {j.createSlave(), j.createSlave(), j.createSlave()};
  258. MatrixProject p = createMatrixProject();
  259. p.getAxes().add(new JDKAxis(Arrays.asList("jdk1.6", "jdk1.5")));
  260. p.getAxes().add(new LabelAxis("label1", Arrays.asList(slaves[0].getNodeName(), slaves[1].getNodeName())));
  261. p.getAxes().add(new LabelAxis("label2", Arrays.asList(slaves[2].getNodeName()))); // make sure single value handling works OK
  262. AxisList o = new AxisList(p.getAxes());
  263. j.configRoundtrip(p);
  264. AxisList n = p.getAxes();
  265. assertEquals(o.size(),n.size());
  266. for (int i = 0; i < o.size(); i++) {
  267. Axis oi = o.get(i);
  268. Axis ni = n.get(i);
  269. assertSame(oi.getClass(), ni.getClass());
  270. assertEquals(oi.name,ni.name);
  271. assertEquals(oi.values,ni.values);
  272. }
  273. DefaultMatrixExecutionStrategyImpl before = new DefaultMatrixExecutionStrategyImpl(true, "foo", Result.UNSTABLE, null);
  274. p.setExecutionStrategy(before);
  275. j.configRoundtrip(p);
  276. j.assertEqualDataBoundBeans(p.getExecutionStrategy(), before);
  277. before = new DefaultMatrixExecutionStrategyImpl(false, null, null, null);
  278. p.setExecutionStrategy(before);
  279. j.configRoundtrip(p);
  280. j.assertEqualDataBoundBeans(p.getExecutionStrategy(), before);
  281. }
  282. @Test
  283. public void testLabelAxes() throws Exception {
  284. MatrixProject p = createMatrixProject();
  285. Slave[] slaves = {j.createSlave(), j.createSlave(), j.createSlave(), j.createSlave()};
  286. p.getAxes().add(new LabelAxis("label1", Arrays.asList(slaves[0].getNodeName(), slaves[1].getNodeName())));
  287. p.getAxes().add(new LabelAxis("label2", Arrays.asList(slaves[2].getNodeName(), slaves[3].getNodeName())));
  288. System.out.println(p.getLabels());
  289. assertEquals(4, p.getLabels().size());
  290. assertTrue(p.getLabels().contains(j.jenkins.getLabel("slave0&&slave2")));
  291. assertTrue(p.getLabels().contains(j.jenkins.getLabel("slave1&&slave2")));
  292. assertTrue(p.getLabels().contains(j.jenkins.getLabel("slave0&&slave3")));
  293. assertTrue(p.getLabels().contains(j.jenkins.getLabel("slave1&&slave3")));
  294. }
  295. /**
  296. * Quiettng down Hudson causes a dead lock if the parent is running but children is in the queue
  297. */
  298. @Issue("JENKINS-4873")
  299. @Test
  300. public void testQuietDownDeadlock() throws Exception {
  301. MatrixProject p = createMatrixProject();
  302. p.setAxes(new AxisList(new TextAxis("foo","1","2")));
  303. p.setRunSequentially(true); // so that we can put the 2nd one in the queue
  304. final OneShotEvent firstStarted = new OneShotEvent();
  305. final OneShotEvent buildCanProceed = new OneShotEvent();
  306. p.getBuildersList().add(new TestBuilder() {
  307. @Override public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException {
  308. firstStarted.signal();
  309. buildCanProceed.block();
  310. return true;
  311. }
  312. });
  313. QueueTaskFuture<MatrixBuild> f = p.scheduleBuild2(0);
  314. // have foo=1 block to make sure the 2nd configuration is in the queue
  315. firstStarted.block();
  316. // enter into the quiet down while foo=2 is still in the queue
  317. j.jenkins.doQuietDown();
  318. buildCanProceed.signal();
  319. // make sure foo=2 still completes. use time out to avoid hang
  320. j.assertBuildStatusSuccess(f.get(10,TimeUnit.SECONDS));
  321. // MatrixProject scheduled after the quiet down shouldn't start
  322. try {
  323. Future g = p.scheduleBuild2(0);
  324. g.get(3,TimeUnit.SECONDS);
  325. fail();
  326. } catch (TimeoutException e) {
  327. // expected
  328. }
  329. }
  330. @Issue("JENKINS-9009")
  331. @Test
  332. public void testTrickyNodeName() throws Exception {
  333. List<String> names = new ArrayList<String>();
  334. names.add(j.createSlave("Sean's Workstation", null).getNodeName());
  335. names.add(j.createSlave("John\"s Workstation", null).getNodeName());
  336. MatrixProject p = createMatrixProject();
  337. p.setAxes(new AxisList(new LabelAxis("label", names)));
  338. j.configRoundtrip(p);
  339. LabelAxis a = (LabelAxis) p.getAxes().find("label");
  340. assertEquals(new HashSet<String>(a.getValues()), new HashSet<String>(names));
  341. }
  342. @Issue("JENKINS-10108")
  343. @Test
  344. public void testTwoFileParams() throws Exception {
  345. MatrixProject p = createMatrixProject();
  346. p.setAxes(new AxisList(new TextAxis("foo","1","2","3","4")));
  347. p.addProperty(new ParametersDefinitionProperty(
  348. new FileParameterDefinition("a.txt",""),
  349. new FileParameterDefinition("b.txt","")
  350. ));
  351. File dir = tmp.getRoot();
  352. List<ParameterValue> params = new ArrayList<ParameterValue>();
  353. for (final String n : new String[] {"aaa", "bbb"}) {
  354. params.add(new FileParameterValue(n + ".txt", File.createTempFile(n, "", dir), n));
  355. }
  356. QueueTaskFuture<MatrixBuild> f = p.scheduleBuild2(0,new LegacyCodeCause(),new ParametersAction(params));
  357. j.assertBuildStatusSuccess(f.get(10,TimeUnit.SECONDS));
  358. }
  359. @Issue("JENKINS-34758")
  360. @Test
  361. public void testParametersAsEnvOnChildren() throws Exception {
  362. MatrixProject p = createMatrixProject();
  363. p.setAxes(new AxisList(new TextAxis("foo","1")));
  364. p.addProperty(new ParametersDefinitionProperty(
  365. new StringParameterDefinition("MY_PARAM","")
  366. ));
  367. // must fail if $MY_PARAM or $foo are not defined in children
  368. p.getBuildersList().add(new Shell("set -eux; echo $MY_PARAM; echo $foo"));
  369. List<ParameterValue> params = new ArrayList<ParameterValue>();
  370. params.add(new StringParameterValue("MY_PARAM", "value1"));
  371. QueueTaskFuture<MatrixBuild> f = p.scheduleBuild2(0, new LegacyCodeCause(), new ParametersAction(params));
  372. j.assertBuildStatusSuccess(f.get());
  373. }
  374. /**
  375. * Verifies that the concurrent build feature works, and makes sure
  376. * that each gets its own unique workspace.
  377. */
  378. @Test
  379. public void testConcurrentBuild() throws Exception {
  380. j.jenkins.setNumExecutors(10);
  381. Method m = Jenkins.class.getDeclaredMethod("updateComputerList"); // TODO is this really necessary?
  382. m.setAccessible(true);
  383. m.invoke(j.jenkins);
  384. MatrixProject p = createMatrixProject();
  385. p.setAxes(new AxisList(new TextAxis("foo","1","2")));
  386. p.setConcurrentBuild(true);
  387. final CountDownLatch latch = new CountDownLatch(4);
  388. final Set<String> dirs = Collections.synchronizedSet(new HashSet<String>());
  389. p.getBuildersList().add(new TestBuilder() {
  390. @Override public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException {
  391. dirs.add(build.getWorkspace().getRemote());
  392. FilePath marker = build.getWorkspace().child("file");
  393. String name = build.getFullDisplayName();
  394. marker.write(name, "UTF-8");
  395. latch.countDown();
  396. latch.await();
  397. assertEquals(name,marker.readToString());
  398. return true;
  399. }
  400. });
  401. // should have gotten all unique names
  402. QueueTaskFuture<MatrixBuild> f1 = p.scheduleBuild2(0);
  403. // get one going
  404. f1.waitForStart();
  405. QueueTaskFuture<MatrixBuild> f2 = p.scheduleBuild2(0);
  406. j.assertBuildStatusSuccess(f1.get());
  407. j.assertBuildStatusSuccess(f2.get());
  408. assertEquals(4, dirs.size());
  409. }
  410. /**
  411. * Test that Actions are passed to configurations
  412. */
  413. @Test
  414. public void testParameterActions() throws Exception {
  415. MatrixProject p = createMatrixProject();
  416. ParametersDefinitionProperty pdp = new ParametersDefinitionProperty(
  417. new StringParameterDefinition("PARAM_A","default_a"),
  418. new StringParameterDefinition("PARAM_B","default_b")
  419. );
  420. p.addProperty(pdp);
  421. List<ParameterValue> values = new ArrayList<ParameterValue>();
  422. for (ParameterDefinition def : pdp.getParameterDefinitions()) {
  423. values.add(def.getDefaultParameterValue());
  424. }
  425. ParametersAction pa = new ParametersAction(values);
  426. MatrixBuild build = p.scheduleBuild2(0,new LegacyCodeCause(), pa).get();
  427. assertEquals(4, build.getRuns().size());
  428. for(MatrixRun run : build.getRuns()) {
  429. ParametersAction pa1 = run.getAction(ParametersAction.class);
  430. assertNotNull(pa1);
  431. assertNotNull(pa1.getParameter("PARAM_A"));
  432. assertNotNull(pa1.getParameter("PARAM_B"));
  433. }
  434. }
  435. /**
  436. * Test that other Actions are passed to configurations
  437. * requires supported version of subversion plugin 1.43+
  438. */
  439. //~ public void testMatrixChildActions() throws Exception {
  440. //~ MatrixProject p = createMatrixProject();
  441. //~ ParametersDefinitionProperty pdp = new ParametersDefinitionProperty(
  442. //~ new StringParameterDefinition("PARAM_A","default_a"),
  443. //~ new StringParameterDefinition("PARAM_B","default_b"),
  444. //~ );
  445. //~ p.addProperty(pdp);
  446. //~ List<Action> actions = new ArrayList<Action>();
  447. //~ actions.add(new RevisionParameterAction(new SvnInfo("http://example.com/svn/repo/",1234)));
  448. //~ actions.add(new ParametersAction( pdp.getParameterDefinitions().collect { return it.getDefaultParameterValue() } ));
  449. //~ MatrixBuild build = p.scheduleBuild2(0,new LegacyCodeCause(), actions).get();
  450. //~ assertEquals(4, build.getRuns().size());
  451. //~ for(MatrixRun run : build.getRuns()) {
  452. //~ ParametersAction pa1 = run.getAction(ParametersAction.class);
  453. //~ assertNotNull(pa1);
  454. //~ ["PARAM_A","PARAM_B"].each{ assertNotNull(pa1.getParameter(it)) };
  455. //~ assertNotNull(run.getAction(RevisionParameterAction.class));
  456. //~ }
  457. //~ }
  458. @Issue("JENKINS-15271")
  459. @LocalData
  460. @Test
  461. public void testUpgrade() throws Exception {
  462. MatrixProject p = j.jenkins.getItemByFullName("x", MatrixProject.class);
  463. assertNotNull(p);
  464. MatrixExecutionStrategy executionStrategy = p.getExecutionStrategy();
  465. assertEquals(DefaultMatrixExecutionStrategyImpl.class, executionStrategy.getClass());
  466. DefaultMatrixExecutionStrategyImpl defaultExecutionStrategy = (DefaultMatrixExecutionStrategyImpl) executionStrategy;
  467. assertFalse(defaultExecutionStrategy.isRunSequentially());
  468. assertNull(defaultExecutionStrategy.getTouchStoneCombinationFilter());
  469. assertNull(defaultExecutionStrategy.getTouchStoneResultCondition());
  470. assertNull(defaultExecutionStrategy.getSorter());
  471. }
  472. @Issue("JENKINS-17337")
  473. @Test public void reload() throws Exception {
  474. MatrixProject p = j.createMatrixProject();
  475. AxisList axes = new AxisList();
  476. axes.add(new TextAxis("p", "only"));
  477. p.setAxes(axes);
  478. String n = p.getFullName();
  479. j.buildAndAssertSuccess(p);
  480. j.jenkins.reload();
  481. p = j.jenkins.getItemByFullName(n, MatrixProject.class);
  482. assertNotNull(p);
  483. MatrixConfiguration c = p.getItem("p=only");
  484. assertNotNull(c);
  485. assertNotNull(c.getBuildByNumber(1));
  486. }
  487. /**
  488. * Given a small master and a big exclusive slave, the fair scheduling would prefer running the flyweight job
  489. * in the slave. But if the scheduler honors the EXCLUSIVE flag, then we should see it built on the master.
  490. *
  491. * Since there's a chance that the fair scheduling just so happens to pick up the master by chance,
  492. * we try multiple jobs to reduce the chance of that happening.
  493. */
  494. @Issue("JENKINS-5076")
  495. @Test
  496. public void dontRunOnExclusiveSlave() throws Exception {
  497. List<MatrixProject> projects = new ArrayList<MatrixProject>();
  498. for (int i = 0; i <= 10; i++) {
  499. MatrixProject m = j.createMatrixProject();
  500. AxisList axes = new AxisList();
  501. axes.add(new TextAxis("p", "only"));
  502. m.setAxes(axes);
  503. projects.add(m);
  504. }
  505. DumbSlave s = new DumbSlave("big", "this is a big slave", j.createTmpDir().getPath(), "20", EXCLUSIVE, "", j.createComputerLauncher(null), RetentionStrategy.NOOP);
  506. j.jenkins.addNode(s);
  507. s.toComputer().connect(false).get(); // connect this guy
  508. for (MatrixProject p : projects) {
  509. MatrixBuild b = j.assertBuildStatusSuccess(p.scheduleBuild2(2));
  510. assertSame(b.getBuiltOn(), j.jenkins);
  511. }
  512. }
  513. @Test @Issue("JENKINS-13554")
  514. public void deletedLockedParentBuild() throws Exception {
  515. MatrixProject p = j.jenkins.createProject(MatrixProject.class, "project");
  516. p.setAxes(new AxisList(new TextAxis("AXIS", "VALUE")));
  517. MatrixBuild build = p.scheduleBuild2(0).get();
  518. MatrixConfiguration c = p.getItem("AXIS=VALUE");
  519. build.keepLog();
  520. build.delete();
  521. assertEquals("parent build is deleted", 0, p.getBuilds().size());
  522. assertEquals("child build is deleted", 0, c.getBuilds().size());
  523. }
  524. @Test @Issue("JENKINS-13554")
  525. public void deletedParentBuildWithLockedChildren() throws Exception {
  526. MatrixProject p = j.jenkins.createProject(MatrixProject.class, "project");
  527. p.setAxes(new AxisList(new TextAxis("AXIS", "VALUE")));
  528. MatrixBuild build = p.scheduleBuild2(0).get();
  529. p.scheduleBuild2(0).get();
  530. MatrixConfiguration c = p.getItem("AXIS=VALUE");
  531. c.getBuildByNumber(2).delete(); // delete newest run
  532. assertNotNull(c.getBuildByNumber(1).getWhyKeepLog());
  533. build.delete();
  534. assertEquals("last parent build should be kept", 1, p.getBuilds().size());
  535. assertEquals("child builds are deleted", 0, c.getBuilds().size());
  536. }
  537. @Test @Issue("JENKINS-13554")
  538. public void discardBuilds() throws Exception {
  539. MatrixProject p = j.jenkins.createProject(MatrixProject.class, "discarder");
  540. p.setAxes(new AxisList(new TextAxis("AXIS", "VALUE")));
  541. // Only last build
  542. p.setBuildDiscarder(new LogRotator("", "1", "", ""));
  543. p.scheduleBuild2(0).get();
  544. p.scheduleBuild2(0).get();
  545. MatrixConfiguration c = p.getItem("AXIS=VALUE");
  546. assertEquals("parent builds are discarded", 1, p.getBuilds().size());
  547. assertEquals("child builds are discarded", 1, c.getBuilds().size());
  548. }
  549. @Test
  550. public void discardArtifacts() throws Exception {
  551. MatrixProject p = j.jenkins.createProject(MatrixProject.class, "discarder");
  552. p.setAxes(new AxisList(new TextAxis("AXIS", "VALUE")));
  553. // Only last artifacts
  554. p.setBuildDiscarder(new LogRotator("", "", "", "1"));
  555. p.getBuildersList().add(new TestBuilder() {
  556. @Override public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException {
  557. build.getWorkspace().child("artifact.zip").write("content", "UTF-8");
  558. return true;
  559. }
  560. });
  561. p.getPublishersList().add(new ArtifactArchiver("artifact.zip", "", false));
  562. p.scheduleBuild2(0).get();
  563. MatrixRun rotated = p.getItem("AXIS=VALUE").getLastBuild();
  564. p.scheduleBuild2(0).get();
  565. MatrixRun last = p.getItem("AXIS=VALUE").getLastBuild();
  566. assertTrue("Artifacts are discarded", rotated.getArtifacts().isEmpty());
  567. assertEquals(1, last.getArtifacts().size());
  568. }
  569. @Test @Issue("JENKINS-13554")
  570. public void deleteBuildWithChildrenOverCLI() throws Exception {
  571. MatrixProject p = j.jenkins.createProject(MatrixProject.class, "project");
  572. p.setAxes(new AxisList(new TextAxis("AXIS", "VALUE")));
  573. p.scheduleBuild2(0).get();
  574. CLICommandInvoker invoker = new CLICommandInvoker(j, new DeleteBuildsCommand());
  575. CLICommandInvoker.Result result = invoker.invokeWithArgs("project", "1");
  576. assertThat(result, CLICommandInvoker.Matcher.succeeded());
  577. assertEquals(0, p.getBuilds().size());
  578. assertEquals(0, p.getItem("AXIS=VALUE").getBuilds().size());
  579. }
  580. }