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