View Javadoc

1   package org.apache.maven.continuum.buildcontroller;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.io.IOException;
24  import java.util.HashMap;
25  import java.util.Map;
26  
27  import org.apache.continuum.taskqueue.BuildProjectTask;
28  import org.apache.maven.continuum.AbstractContinuumTest;
29  import org.apache.maven.continuum.core.action.AbstractContinuumAction;
30  import org.apache.maven.continuum.model.project.BuildDefinition;
31  import org.apache.maven.continuum.model.project.Project;
32  import org.apache.maven.continuum.model.project.ProjectGroup;
33  import org.apache.maven.continuum.project.builder.ContinuumProjectBuilder;
34  import org.apache.maven.continuum.project.builder.ContinuumProjectBuilderException;
35  import org.apache.maven.continuum.project.builder.ContinuumProjectBuildingResult;
36  import org.apache.maven.continuum.project.builder.maven.MavenTwoContinuumProjectBuilder;
37  import org.codehaus.plexus.action.ActionManager;
38  import org.codehaus.plexus.taskqueue.Task;
39  import org.codehaus.plexus.taskqueue.TaskQueue;
40  import org.codehaus.plexus.taskqueue.execution.TaskQueueExecutor;
41  import org.codehaus.plexus.util.FileUtils;
42  
43  /**
44   * @author <a href="mailto:kenney@apache.org">Kenney Westerhof</a>
45   */
46  public class BuildProjectTaskExecutorTest
47      extends AbstractContinuumTest
48  {
49      private ContinuumProjectBuilder projectBuilder;
50  
51      private TaskQueue buildQueue;
52  
53      private TaskQueueExecutor taskQueueExecutor;
54  
55      private ActionManager actionManager;
56  
57      public void setUp()
58          throws Exception
59      {
60          try
61          {
62              super.setUp();
63  
64              projectBuilder =
65                  (ContinuumProjectBuilder) lookup( ContinuumProjectBuilder.ROLE, MavenTwoContinuumProjectBuilder.ID );
66  
67              buildQueue = (TaskQueue) lookup( TaskQueue.ROLE, "build-project" );
68  
69              taskQueueExecutor = (TaskQueueExecutor) lookup( TaskQueueExecutor.ROLE, "build-project" );
70  
71              actionManager = (ActionManager) lookup( ActionManager.ROLE );
72          }
73          catch ( Exception e )
74          {
75              e.printStackTrace();
76              throw e;
77          }
78      }
79  
80      public void testAutomaticCancellation()
81          throws Exception
82      {
83          runTimeoutProject( 13000 );
84  
85          long taskStartTime = System.currentTimeMillis();
86  
87          // should be killed in 5 secs, plus slack
88          waitForTaskDead( 10000 );
89  
90          // the project will sleep for 15 seconds and then write a file.
91          // Make sure we sleep at least that long and then check for the file;
92          // it should not be there.
93  
94          long taskWaitTime = 15000 - ( System.currentTimeMillis() - taskStartTime );
95  
96          System.err.println( "Sleeping " + taskWaitTime + "ms" );
97          Thread.sleep( taskWaitTime );
98  
99          assertFalse( "Build completed", getTestFile( "src/test-projects/timeout/target/TEST-COMPLETED" ).exists() );
100     }
101 
102     public void testManualCancellation()
103         throws Exception
104     {
105         BuildProjectTask task = runTimeoutProject( 0 );
106 
107         assertFalse( "Build completed", getTestFile( "src/test-projects/timeout/target/TEST-COMPLETED" ).exists() );
108 
109         long taskStartTime = System.currentTimeMillis();
110 
111         assertTrue( taskQueueExecutor.cancelTask( task ) );
112 
113         waitForTaskDead( 5000 );
114 
115         long taskWaitTime = 15000 - ( System.currentTimeMillis() - taskStartTime );
116 
117         System.err.println( "Sleeping " + taskWaitTime + "ms" );
118         Thread.sleep( taskWaitTime );
119 
120         assertFalse( "Build completed", getTestFile( "src/test-projects/timeout/target/TEST-COMPLETED" ).exists() );
121     }
122 
123     public void testNoCancellation()
124         throws Exception
125     {
126         runTimeoutProject( 0 );
127 
128         waitForFile( "src/test-projects/timeout/target/TEST-COMPLETED", 20000 );
129 
130         waitForTaskDead( 10000 );
131     }
132 
133     private void waitForFile( String file, int max )
134         throws InterruptedException
135     {
136         long time = System.currentTimeMillis();
137 
138         for ( int i = 0; i < max / 10; i++ )
139         {
140             if ( getTestFile( file ).exists() )
141             {
142                 break;
143             }
144             Thread.sleep( 10 );
145         }
146 
147         System.err.println( "Waited " + ( System.currentTimeMillis() - time ) + "ms for file " + file );
148 
149         assertTrue( "File " + file, getTestFile( file ).exists() );
150     }
151 
152     private void waitForTaskDead( int maxWait )
153         throws InterruptedException
154     {
155         for ( int i = 0; i < maxWait / 10; i++ )
156         {
157             if ( taskQueueExecutor.getCurrentTask() == null )
158             {
159                 break;
160             }
161 
162             Thread.sleep( 10 );
163         }
164 
165         assertNull( "No current task", taskQueueExecutor.getCurrentTask() );
166     }
167 
168     /**
169      * Runs the timeout test project through the build queue and return when the unit test in it has started. The
170      * project contains a unit test that sleeps for 15 seconds.
171      *
172      * @param maxRunTime maximum time the build may run before it's auto cancelled; 0 means forever.
173      * @return
174      * @throws Exception
175      */
176     private BuildProjectTask runTimeoutProject( int maxRunTime )
177         throws Exception
178     {
179         BuildProjectTask task = createTask( maxRunTime );
180 
181         FileUtils.forceDelete( getTestFile( "src/test-projects/timeout/target/TEST-STARTED" ) );
182         FileUtils.forceDelete( getTestFile( "src/test-projects/timeout/target/TEST-COMPLETED" ) );
183 
184         System.err.println( "Queueing build" );
185 
186         this.buildQueue.put( task );
187 
188         System.err.println( "Waiting for task to start" );
189 
190         Task curTask;
191 
192         // Sleep at most 10 seconds for the task to start
193         for ( int i = 0; i < 1000; i++ )
194         {
195             curTask = taskQueueExecutor.getCurrentTask();
196 
197             if ( curTask != null )
198             {
199                 break;
200             }
201 
202             Thread.sleep( 10 );
203         }
204 
205         assertNotNull( "Task not started", task );
206 
207         // wait for the start file to be written
208 
209         waitForFile( "src/test-projects/timeout/target/TEST-STARTED", 10000 );
210 
211         System.err.println( "Task started, TEST-STARTED file created." );
212 
213         return task;
214     }
215 
216     private BuildProjectTask createTask( int maxRunTime )
217         throws Exception
218     {
219         ProjectGroup projectGroup = getProjectGroup( "src/test-projects/timeout/pom.xml" );
220         Project project = (Project) projectGroup.getProjects().get( 0 );
221 
222         BuildDefinition buildDefinition = new BuildDefinition();
223         buildDefinition.setId( 0 );
224         buildDefinition.setGoals( "install" );
225 
226         projectGroup.addBuildDefinition( buildDefinition );
227 
228         Map<String, Object> pgContext = new HashMap<String, Object>();
229 
230         AbstractContinuumAction.setWorkingDirectory( pgContext, project.getWorkingDirectory() );
231 
232         AbstractContinuumAction.setUnvalidatedProjectGroup( pgContext, projectGroup );
233 
234         actionManager.lookup( "validate-project-group" ).execute( pgContext );
235 
236         actionManager.lookup( "store-project-group" ).execute( pgContext );
237 
238         int projectGroupId = AbstractContinuumAction.getProjectGroupId( pgContext );
239 
240         projectGroup = getProjectGroupDao().getProjectGroupWithBuildDetailsByProjectGroupId( projectGroupId );
241 
242         project = (Project) projectGroup.getProjects().get( 0 );
243 
244         buildDefinition = (BuildDefinition) projectGroup.getBuildDefinitions().get( 0 );
245 
246         // projectGroup = continuumStore.addProjectGroup( projectGroup );
247 
248         BuildProjectTask task = new BuildProjectTask( project.getId(), buildDefinition.getId(), 0, project.getName(),
249                                                       buildDefinition.getDescription(), null, projectGroupId );
250 
251         task.setMaxExecutionTime( maxRunTime );
252 
253         return task;
254     }
255 
256     private ProjectGroup getProjectGroup( String pomResource )
257         throws ContinuumProjectBuilderException, IOException
258     {
259         File pom = getTestFile( pomResource );
260 
261         assertNotNull( "Can't find project " + pomResource, pom );
262 
263         ContinuumProjectBuildingResult result = projectBuilder.buildProjectsFromMetadata( pom.toURL(), null, null );
264 
265         // some assertions to make sure our expectations match. This is NOT
266         // meant as a unit test for the projectbuilder!
267 
268         assertNotNull( "Project list not null", result.getProjects() );
269 
270         assertEquals( "#Projectgroups", 1, result.getProjectGroups().size() );
271 
272         ProjectGroup pg = result.getProjectGroups().get( 0 );
273 
274         // If the next part fails, remove this code! Then result.getProjects
275         // might be empty, and result.projectgroups[0].getProjects contains
276         // the single project!
277 
278         assertEquals( "#Projects in result", 1, result.getProjects().size() );
279 
280         Project p = result.getProjects().get( 0 );
281 
282         pg.addProject( p );
283 
284         p.setWorkingDirectory( pom.getParent() );
285 
286         return pg;
287     }
288 }