File D:\maven-qcr-plugin-testsunitaires\qcr4java\jenkins-master\target\site\qc\test\src\test\java\hudson\slaves\NodeProvisionerTest.java.html

1 /*
2 * The MIT License
3 *
4 * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi
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.slaves;
25
26 import hudson.BulkChange;
27 import hudson.Launcher;
28 import hudson.model.*;
29 import hudson.slaves.NodeProvisioner.NodeProvisionerInvoker;
30 import hudson.tasks.Builder;
31
32 import org.jvnet.hudson.test.HudsonTestCase;
33 import org.jvnet.hudson.test.SleepBuilder;
34
35 import java.io.IOException;
36 import java.util.ArrayList;
37 import java.util.Collections;
38 import java.util.List;
39 import java.util.concurrent.CountDownLatch;
40 import java.util.concurrent.Future;
41 import java.util.concurrent.TimeUnit;
42 import java.util.concurrent.TimeoutException;
43
44 /**
45 * @author Kohsuke Kawaguchi
46 */
47 public class NodeProvisionerTest extends HudsonTestCase {
48 private int original;
49
50 @Override
51 protected void setUp() throws Exception {
52 original = LoadStatistics.CLOCK;
53 LoadStatistics.CLOCK = 10; // run x1000 the regular speed to speed up the test
54 NodeProvisionerInvoker.INITIALDELAY = 100;
55 NodeProvisionerInvoker.RECURRENCEPERIOD = 10;
56 super.setUp();
57 }
58
59 @Override
60 protected void tearDown() throws Exception {
61 super.tearDown();
62 LoadStatistics.CLOCK = original;
63 NodeProvisionerInvoker.INITIALDELAY = original*10;
64 NodeProvisionerInvoker.RECURRENCEPERIOD = original;
65 }
66
67 public void testDummy() {} // just to make Surefire happy
68
69 /**
70 * Latch synchronization primitive that waits for N thread to pass the checkpoint.
71 * <p>
72 * This is used to make sure we get a set of builds that run long enough.
73 */
74 static class Latch {
75 /** Initial value */
76 public final CountDownLatch counter;
77 private final int init;
78
79 Latch(int n) {
80 this.init = n;
81 this.counter = new CountDownLatch(n);
82 }
83
84 void block() throws InterruptedException {
85 this.counter.countDown();
86 this.counter.await(60, TimeUnit.SECONDS);
87 }
88
89 /**
90 * Creates a builder that blocks until the latch opens.
91 */
92 public Builder createBuilder() {
93 return new Builder() {
94 public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException {
95 block();
96 return true;
97 }
98 };
99 }
100 }
101
102 /**
103 * Scenario: schedule a build and see if one slave is provisioned.
104 */
105 public void _testAutoProvision() throws Exception {// excluded since it's fragile
106 BulkChange bc = new BulkChange(jenkins);
107 try {
108 DummyCloudImpl cloud = initHudson(10);
109
110
111 FreeStyleProject p = createJob(new SleepBuilder(10));
112
113 Future<FreeStyleBuild> f = p.scheduleBuild2(0);
114 f.get(30, TimeUnit.SECONDS); // if it's taking too long, abort.
115
116 // since there's only one job, we expect there to be just one slave
117 assertEquals(1,cloud.numProvisioned);
118 } finally {
119 bc.abort();
120 }
121 }
122
123 /**
124 * Scenario: we got a lot of jobs all of the sudden, and we need to fire up a few nodes.
125 */
126 public void _testLoadSpike() throws Exception {// excluded since it's fragile
127 BulkChange bc = new BulkChange(jenkins);
128 try {
129 DummyCloudImpl cloud = initHudson(0);
130
131 verifySuccessfulCompletion(buildAll(create5SlowJobs(new Latch(5))));
132
133 // the time it takes to complete a job is eternally long compared to the time it takes to launch
134 // a new slave, so in this scenario we end up allocating 5 slaves for 5 jobs.
135 assertEquals(5,cloud.numProvisioned);
136 } finally {
137 bc.abort();
138 }
139 }
140
141 /**
142 * Scenario: make sure we take advantage of statically configured slaves.
143 */
144 public void _testBaselineSlaveUsage() throws Exception {// excluded since it's fragile
145 BulkChange bc = new BulkChange(jenkins);
146 try {
147 DummyCloudImpl cloud = initHudson(0);
148 // add slaves statically upfront
149 createSlave().toComputer().connect(false).get();
150 createSlave().toComputer().connect(false).get();
151
152 verifySuccessfulCompletion(buildAll(create5SlowJobs(new Latch(5))));
153
154 // we should have used two static slaves, thus only 3 slaves should have been provisioned
155 assertEquals(3,cloud.numProvisioned);
156 } finally {
157 bc.abort();
158 }
159 }
160
161 /**
162 * Scenario: loads on one label shouldn't translate to load on another label.
163 */
164 public void _testLabels() throws Exception {// excluded since it's fragile
165 BulkChange bc = new BulkChange(jenkins);
166 try {
167 DummyCloudImpl cloud = initHudson(0);
168 Label blue = jenkins.getLabel("blue");
169 Label red = jenkins.getLabel("red");
170 cloud.label = red;
171
172 // red jobs
173 List<FreeStyleProject> redJobs = create5SlowJobs(new Latch(5));
174 for (FreeStyleProject p : redJobs)
175 p.setAssignedLabel(red);
176
177 // blue jobs
178 List<FreeStyleProject> blueJobs = create5SlowJobs(new Latch(5));
179 for (FreeStyleProject p : blueJobs)
180 p.setAssignedLabel(blue);
181
182 // build all
183 List<Future<FreeStyleBuild>> blueBuilds = buildAll(blueJobs);
184 verifySuccessfulCompletion(buildAll(redJobs));
185
186 // cloud should only give us 5 nodes for 5 red jobs
187 assertEquals(5,cloud.numProvisioned);
188
189 // and all blue jobs should be still stuck in the queue
190 for (Future<FreeStyleBuild> bb : blueBuilds)
191 assertFalse(bb.isDone());
192 } finally {
193 bc.abort();
194 }
195 }
196
197
198 private FreeStyleProject createJob(Builder builder) throws IOException {
199 FreeStyleProject p = createFreeStyleProject();
200 p.setAssignedLabel(null); // let it roam free, or else it ties itself to the master since we have no slaves
201 p.getBuildersList().add(builder);
202 return p;
203 }
204
205 private DummyCloudImpl initHudson(int delay) throws IOException {
206 // start a dummy service
207 DummyCloudImpl cloud = new DummyCloudImpl(this, delay);
208 jenkins.clouds.add(cloud);
209
210 // no build on the master, to make sure we get everything from the cloud
211 jenkins.setNumExecutors(0);
212 jenkins.setNodes(Collections.<Node>emptyList());
213 return cloud;
214 }
215
216 private List<FreeStyleProject> create5SlowJobs(Latch l) throws IOException {
217 List<FreeStyleProject> jobs = new ArrayList<FreeStyleProject>();
218 for( int i=0; i<l.init; i++)
219 //set a large delay, to simulate the situation where we need to provision more slaves
220 // to keep up with the load
221 jobs.add(createJob(l.createBuilder()));
222 return jobs;
223 }
224
225 /**
226 * Builds all the given projects at once.
227 */
228 private List<Future<FreeStyleBuild>> buildAll(List<FreeStyleProject> jobs) {
229 System.out.println("Scheduling builds for "+jobs.size()+" jobs");
230 List<Future<FreeStyleBuild>> builds = new ArrayList<Future<FreeStyleBuild>>();
231 for (FreeStyleProject job : jobs)
232 builds.add(job.scheduleBuild2(0));
233 return builds;
234 }
235
236 private void verifySuccessfulCompletion(List<Future<FreeStyleBuild>> builds) throws Exception {
237 System.out.println("Waiting for a completion");
238 for (Future<FreeStyleBuild> f : builds) {
239 try {
240 assertBuildStatus(Result.SUCCESS, f.get(90, TimeUnit.SECONDS));
241 } catch (TimeoutException e) {
242 // time out so that the automated test won't hang forever, even when we have bugs
243 System.out.println("Build didn't complete in time");
244 throw e;
245 }
246 }
247 }
248 }
249