View Javadoc

1   package org.apache.continuum.buildmanager;
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.buildqueue.BuildQueueService;
23  import org.apache.continuum.dao.BuildDefinitionDao;
24  import org.apache.continuum.dao.ProjectDao;
25  import org.apache.continuum.taskqueue.BuildProjectTask;
26  import org.apache.continuum.taskqueue.CheckOutTask;
27  import org.apache.continuum.taskqueue.OverallBuildQueue;
28  import org.apache.continuum.taskqueue.PrepareBuildProjectsTask;
29  import org.apache.continuum.taskqueueexecutor.ParallelBuildsThreadedTaskQueueExecutor;
30  import org.apache.continuum.utils.build.BuildTrigger;
31  import org.apache.maven.continuum.configuration.ConfigurationService;
32  import org.apache.maven.continuum.model.project.BuildDefinition;
33  import org.apache.maven.continuum.model.project.BuildQueue;
34  import org.apache.maven.continuum.model.project.Project;
35  import org.apache.maven.continuum.model.project.Schedule;
36  import org.apache.maven.continuum.store.ContinuumStoreException;
37  import org.codehaus.plexus.spring.PlexusInSpringTestCase;
38  import org.codehaus.plexus.taskqueue.Task;
39  import org.codehaus.plexus.taskqueue.TaskQueue;
40  import org.codehaus.plexus.taskqueue.TaskQueueException;
41  import org.codehaus.plexus.taskqueue.execution.TaskQueueExecutor;
42  import org.jmock.Expectations;
43  import org.jmock.Mockery;
44  import org.jmock.integration.junit3.JUnit3Mockery;
45  import org.jmock.lib.legacy.ClassImposteriser;
46  
47  import java.io.File;
48  import java.util.ArrayList;
49  import java.util.Collections;
50  import java.util.HashMap;
51  import java.util.List;
52  import java.util.Map;
53  
54  /**
55   * ParallelBuildsManagerTest
56   *
57   * @author <a href="mailto:oching@apache.org">Maria Odea Ching</a>
58   */
59  public class ParallelBuildsManagerTest
60      extends PlexusInSpringTestCase
61  {
62      private ParallelBuildsManager buildsManager;
63  
64      private Mockery context;
65  
66      private BuildDefinitionDao buildDefinitionDao;
67  
68      private ProjectDao projectDao;
69  
70      private ConfigurationService configurationService;
71  
72      private OverallBuildQueue overallBuildQueue;
73  
74      private TaskQueue buildQueue;
75  
76      private TaskQueue checkoutQueue;
77  
78      private TaskQueue prepareBuildQueue;
79  
80      private List<Project> projects;
81  
82      private TaskQueueExecutor buildTaskQueueExecutor;
83  
84      private TaskQueueExecutor checkoutTaskQueueExecutor;
85  
86      private TaskQueueExecutor prepareBuildTaskQueueExecutor;
87  
88      @Override
89      public void setUp()
90          throws Exception
91      {
92          super.setUp();
93  
94          buildsManager = (ParallelBuildsManager) lookup( BuildsManager.class, "parallel" );
95  
96          context = new JUnit3Mockery();
97          context.setImposteriser( ClassImposteriser.INSTANCE );
98  
99          buildDefinitionDao = context.mock( BuildDefinitionDao.class );
100 
101         buildsManager.setBuildDefinitionDao( buildDefinitionDao );
102 
103         configurationService = context.mock( ConfigurationService.class );
104 
105         buildsManager.setConfigurationService( configurationService );
106 
107         BuildQueueService buildQueueService = context.mock( BuildQueueService.class );
108 
109         buildsManager.setBuildQueueService( buildQueueService );
110 
111         buildQueue = context.mock( TaskQueue.class, "build-queue" );
112 
113         checkoutQueue = context.mock( TaskQueue.class, "checkout-queue" );
114 
115         prepareBuildQueue = context.mock( TaskQueue.class, "prepare-build-queue" );
116 
117         projectDao = context.mock( ProjectDao.class );
118 
119         buildsManager.setProjectDao( projectDao );
120 
121         buildTaskQueueExecutor = context.mock( TaskQueueExecutor.class, "build-task-queue" );
122 
123         checkoutTaskQueueExecutor = context.mock( TaskQueueExecutor.class, "checkout-task-queue" );
124 
125         prepareBuildTaskQueueExecutor = context.mock( TaskQueueExecutor.class, "prepare-build-task-queue" );
126     }
127 
128     @Override
129     public void tearDown()
130         throws Exception
131     {
132         super.tearDown();
133 
134         buildsManager = null;
135     }
136 
137     private List<BuildQueue> getBuildQueues( int start, int end )
138     {
139         List<BuildQueue> buildQueues = new ArrayList<BuildQueue>();
140         for ( int i = start; i <= end; i++ )
141         {
142             BuildQueue buildQueue = new BuildQueue();
143             buildQueue.setId( i );
144             if ( i == 1 )
145             {
146                 buildQueue.setName( ConfigurationService.DEFAULT_BUILD_QUEUE_NAME );
147             }
148             else
149             {
150                 buildQueue.setName( "BUILD_QUEUE_" + String.valueOf( i ) );
151             }
152             buildQueues.add( buildQueue );
153         }
154 
155         return buildQueues;
156     }
157 
158     private Schedule getSchedule( int id, int start, int end )
159     {
160         Schedule schedule = new Schedule();
161         schedule.setId( id );
162         schedule.setName( "DEFAULT_SCHEDULE" );
163         schedule.setCronExpression( "0 0 * * * ?" );
164         schedule.setDelay( 100 );
165         schedule.setMaxJobExecutionTime( 10000 );
166         schedule.setBuildQueues( getBuildQueues( start, end ) );
167 
168         return schedule;
169     }
170 
171     public void setupMockOverallBuildQueues()
172         throws Exception
173     {
174         Map<Integer, OverallBuildQueue> overallBuildQueues = Collections.synchronizedMap(
175             new HashMap<Integer, OverallBuildQueue>() );
176         overallBuildQueue = context.mock( OverallBuildQueue.class );
177         for ( int i = 1; i <= 5; i++ )
178         {
179             overallBuildQueues.put( i, overallBuildQueue );
180         }
181 
182         buildsManager.setOverallBuildQueues( overallBuildQueues );
183     }
184 
185     // build project recordings
186     private void recordStartOfBuildProjectSequence()
187         throws TaskQueueException, ContinuumStoreException
188     {
189         context.checking( new Expectations()
190         {
191             {
192                 exactly( 5 ).of( overallBuildQueue ).isInBuildQueue( with( any( int.class ) ) );
193                 will( returnValue( false ) );
194 
195                 exactly( 5 ).of( buildTaskQueueExecutor ).getCurrentTask();
196                 will( returnValue( null ) );
197 
198                 one( projectDao ).getProjectsInGroup( with( any( int.class ) ) );
199                 will( returnValue( projects ) );
200 
201                 one( configurationService ).getNumberOfBuildsInParallel();
202                 will( returnValue( 2 ) );
203 
204                 exactly( 2 ).of( overallBuildQueue ).getBuildQueue();
205                 will( returnValue( buildQueue ) );
206 
207                 exactly( 7 ).of( overallBuildQueue ).getBuildTaskQueueExecutor();
208                 will( returnValue( buildTaskQueueExecutor ) );
209             }
210         } );
211     }
212 
213     private void recordBuildProjectBuildQueuesAreEmpty()
214         throws TaskQueueException, ContinuumStoreException
215     {
216         // shouldn't only the build queues attached to the schedule be checked?
217         recordStartOfBuildProjectSequence();
218 
219         final List<Task> tasks = new ArrayList<Task>();
220         context.checking( new Expectations()
221         {
222             {
223                 exactly( 2 ).of( buildQueue ).getQueueSnapshot();
224                 will( returnValue( tasks ) );
225 
226                 exactly( 2 ).of( buildTaskQueueExecutor ).getCurrentTask();
227                 will( returnValue( null ) );
228 
229                 one( overallBuildQueue ).getName();
230                 will( returnValue( "BUILD_QUEUE_2" ) );
231             }
232         } );
233 
234         recordAddToBuildQueue();
235     }
236 
237     private void recordAddToBuildQueue()
238         throws TaskQueueException
239     {
240         context.checking( new Expectations()
241         {
242             {
243                 one( overallBuildQueue ).addToBuildQueue( with( any( BuildProjectTask.class ) ) );
244             }
245         } );
246     }
247 
248     // checkout project recordings
249     private void recordStartOfCheckoutProjectSequence()
250         throws TaskQueueException
251     {
252         context.checking( new Expectations()
253         {
254             {
255                 exactly( 5 ).of( overallBuildQueue ).isInCheckoutQueue( with( any( int.class ) ) );
256                 will( returnValue( false ) );
257 
258                 one( configurationService ).getNumberOfBuildsInParallel();
259                 will( returnValue( 2 ) );
260 
261                 exactly( 2 ).of( overallBuildQueue ).getCheckoutQueue();
262                 will( returnValue( checkoutQueue ) );
263 
264                 exactly( 2 ).of( overallBuildQueue ).getCheckoutTaskQueueExecutor();
265                 will( returnValue( checkoutTaskQueueExecutor ) );
266             }
267         } );
268 
269     }
270 
271     private void recordCheckoutProjectBuildQueuesAreEmpty()
272         throws TaskQueueException
273     {
274         recordStartOfCheckoutProjectSequence();
275 
276         final List<Task> tasks = new ArrayList<Task>();
277         context.checking( new Expectations()
278         {
279             {
280                 exactly( 2 ).of( checkoutQueue ).getQueueSnapshot();
281                 will( returnValue( tasks ) );
282 
283                 exactly( 2 ).of( checkoutTaskQueueExecutor ).getCurrentTask();
284                 will( returnValue( null ) );
285 
286                 one( overallBuildQueue ).getName();
287                 will( returnValue( "BUILD_QUEUE_2" ) );
288             }
289         } );
290 
291         recordAddToCheckoutQueue();
292     }
293 
294     private void recordAddToCheckoutQueue()
295         throws TaskQueueException
296     {
297         context.checking( new Expectations()
298         {
299             {
300                 one( overallBuildQueue ).addToCheckoutQueue( with( any( CheckOutTask.class ) ) );
301             }
302         } );
303     }
304 
305     // prepare build project recordings
306     private void recordStartOfPrepareBuildProjectSequence()
307         throws TaskQueueException, ContinuumStoreException
308     {
309         final BuildDefinition buildDef = new BuildDefinition();
310         buildDef.setId( 1 );
311         buildDef.setSchedule( getSchedule( 1, 1, 2 ) );
312 
313         context.checking( new Expectations()
314         {
315             {
316                 exactly( 5 ).of( overallBuildQueue ).isInPrepareBuildQueue( with( any( int.class ) ), with( any(
317                     int.class ) ) );
318                 will( returnValue( false ) );
319 
320                 one( buildDefinitionDao ).getBuildDefinition( 1 );
321                 will( returnValue( buildDef ) );
322 
323                 one( configurationService ).getNumberOfBuildsInParallel();
324                 will( returnValue( 2 ) );
325 
326                 exactly( 2 ).of( overallBuildQueue ).getPrepareBuildQueue();
327                 will( returnValue( prepareBuildQueue ) );
328 
329                 exactly( 2 ).of( overallBuildQueue ).getPrepareBuildTaskQueueExecutor();
330                 will( returnValue( prepareBuildTaskQueueExecutor ) );
331             }
332         } );
333     }
334 
335     private void recordPrepareBuildProjectPrepareBuildQueuesAreEmpty()
336         throws TaskQueueException, ContinuumStoreException
337     {
338         recordStartOfPrepareBuildProjectSequence();
339 
340         final List<Task> tasks = new ArrayList<Task>();
341         context.checking( new Expectations()
342         {
343             {
344                 exactly( 2 ).of( prepareBuildQueue ).getQueueSnapshot();
345                 will( returnValue( tasks ) );
346 
347                 exactly( 2 ).of( prepareBuildTaskQueueExecutor ).getCurrentTask();
348                 will( returnValue( null ) );
349 
350                 one( overallBuildQueue ).getName();
351                 will( returnValue( "BUILD_QUEUE_2" ) );
352             }
353         } );
354 
355         recordAddToPrepareBuildQueue();
356     }
357 
358     private void recordAddToPrepareBuildQueue()
359         throws TaskQueueException
360     {
361         context.checking( new Expectations()
362         {
363             {
364                 one( overallBuildQueue ).addToPrepareBuildQueue( with( any( PrepareBuildProjectsTask.class ) ) );
365             }
366         } );
367     }
368 
369     // start of test cases..
370 
371     public void testContainer()
372         throws Exception
373     {
374         buildsManager.setContainer( getContainer() );
375 
376         buildsManager.isProjectInAnyCurrentBuild( 1 );
377 
378         assertTrue( true );
379     }
380 
381     public void testBuildProjectNoProjectQueuedInAnyOverallBuildQueues()
382         throws Exception
383     {
384         setupMockOverallBuildQueues();
385 
386         BuildDefinition buildDef = new BuildDefinition();
387         buildDef.setId( 1 );
388         buildDef.setSchedule( getSchedule( 1, 1, 2 ) );
389 
390         recordBuildProjectBuildQueuesAreEmpty();
391 
392         buildsManager.buildProject( 1, buildDef, "continuum-project-test-1", new BuildTrigger( 1, "test-user" ), null,
393                                     1 );
394 
395         context.assertIsSatisfied();
396     }
397 
398     public void testBuildProjectProjectsAreAlreadyQueuedInOverallBuildQueues()
399         throws Exception
400     {
401         setupMockOverallBuildQueues();
402 
403         BuildDefinition buildDef = new BuildDefinition();
404         buildDef.setId( 1 );
405         buildDef.setSchedule( getSchedule( 1, 1, 2 ) );
406 
407         recordBuildProjectBuildQueuesAreEmpty();
408 
409         buildsManager.buildProject( 1, buildDef, "continuum-project-test-1", new BuildTrigger( 1, "test-user" ), null,
410                                     1 );
411         context.assertIsSatisfied();
412 
413         //queue second project - 1st queue is not empty, 2nd queue is empty 
414         recordStartOfBuildProjectSequence();
415 
416         // the first build queue already has a task queued
417         final List<Task> tasks = new ArrayList<Task>();
418         final List<Task> tasksOfFirstBuildQueue = new ArrayList<Task>();
419         tasksOfFirstBuildQueue.add( new BuildProjectTask( 2, 1, new BuildTrigger( 1, "test-user" ),
420                                                           "continuum-project-test-2", buildDef.getDescription(), null,
421                                                           2 ) );
422         context.checking( new Expectations()
423         {
424             {
425                 one( buildQueue ).getQueueSnapshot();
426                 will( returnValue( tasksOfFirstBuildQueue ) );
427 
428                 // the second build queue has no tasks queued, so it should return 0
429                 one( buildQueue ).getQueueSnapshot();
430                 will( returnValue( tasks ) );
431 
432                 exactly( 2 ).of( buildTaskQueueExecutor ).getCurrentTask();
433                 will( returnValue( null ) );
434 
435                 one( overallBuildQueue ).getName();
436                 will( returnValue( "BUILD_QUEUE_3" ) );
437             }
438         } );
439 
440         recordAddToBuildQueue();
441 
442         buildsManager.buildProject( 2, buildDef, "continuum-project-test-2", new BuildTrigger( 1, "test-user" ), null,
443                                     2 );
444         context.assertIsSatisfied();
445 
446         // queue third project - both queues have 1 task queued each
447         recordStartOfBuildProjectSequence();
448 
449         // both queues have 1 task each        
450         context.checking( new Expectations()
451         {
452             {
453                 exactly( 2 ).of( buildQueue ).getQueueSnapshot();
454                 will( returnValue( tasksOfFirstBuildQueue ) );
455 
456                 exactly( 2 ).of( buildTaskQueueExecutor ).getCurrentTask();
457                 will( returnValue( null ) );
458 
459                 one( overallBuildQueue ).getName();
460                 will( returnValue( "BUILD_QUEUE_2" ) );
461             }
462         } );
463 
464         recordAddToBuildQueue();
465 
466         buildsManager.buildProject( 3, buildDef, "continuum-project-test-3", new BuildTrigger( 1, "test-user" ), null,
467                                     3 );
468         context.assertIsSatisfied();
469     }
470 
471     public void testRemoveProjectFromBuildQueue()
472         throws Exception
473     {
474         setupMockOverallBuildQueues();
475 
476         context.checking( new Expectations()
477         {
478             {
479                 one( overallBuildQueue ).isInBuildQueue( 1 );
480                 will( returnValue( true ) );
481 
482                 one( overallBuildQueue ).removeProjectFromBuildQueue( 1 );
483             }
484         } );
485 
486         buildsManager.removeProjectFromBuildQueue( 1 );
487         context.assertIsSatisfied();
488     }
489 
490     public void testRemoveProjectsFromBuildQueue()
491         throws Exception
492     {
493         setupMockOverallBuildQueues();
494         int[] projectIds = new int[]{1, 2, 3};
495 
496         context.checking( new Expectations()
497         {
498             {
499                 exactly( 3 ).of( overallBuildQueue ).isInBuildQueue( with( any( int.class ) ) );
500                 will( returnValue( true ) );
501 
502                 exactly( 3 ).of( overallBuildQueue ).removeProjectFromBuildQueue( with( any( int.class ) ) );
503             }
504         } );
505 
506         buildsManager.removeProjectsFromBuildQueue( projectIds );
507         context.assertIsSatisfied();
508     }
509 
510     public void testCheckoutProjectSingle()
511         throws Exception
512     {
513         setupMockOverallBuildQueues();
514 
515         BuildDefinition buildDef = new BuildDefinition();
516         buildDef.setId( 1 );
517         buildDef.setSchedule( getSchedule( 1, 1, 2 ) );
518 
519         recordCheckoutProjectBuildQueuesAreEmpty();
520 
521         buildsManager.checkoutProject( 1, "continuum-project-test-1", new File( getBasedir(),
522                                                                                 "/target/test-working-dir/1" ), null,
523                                        "dummy", "dummypass", buildDef, null );
524         context.assertIsSatisfied();
525     }
526 
527     public void testCheckoutProjectMultiple()
528         throws Exception
529     {
530         setupMockOverallBuildQueues();
531 
532         BuildDefinition buildDef = new BuildDefinition();
533         buildDef.setId( 1 );
534         buildDef.setSchedule( getSchedule( 1, 1, 2 ) );
535 
536         recordCheckoutProjectBuildQueuesAreEmpty();
537 
538         buildsManager.checkoutProject( 1, "continuum-project-test-1", new File( getBasedir(),
539                                                                                 "/target/test-working-dir/1" ), null,
540                                        "dummy", "dummypass", buildDef, null );
541         context.assertIsSatisfied();
542 
543         // queue second project - 1st queue has 1 task while 2nd queue is empty; project should be queued in
544         //      2nd queue
545         recordStartOfCheckoutProjectSequence();
546 
547         final List<Task> tasks = new ArrayList<Task>();
548 
549         final List<Task> tasksInFirstCheckoutQueue = new ArrayList<Task>();
550         tasksInFirstCheckoutQueue.add( new CheckOutTask( 1, new File( getBasedir(), "/target/test-working-dir/1" ),
551                                                          "continuum-project-test-1", "dummy", "dummypass", null,
552                                                          null ) );
553 
554         context.checking( new Expectations()
555         {
556             {
557                 one( checkoutQueue ).getQueueSnapshot();
558                 will( returnValue( tasksInFirstCheckoutQueue ) );
559 
560                 one( checkoutQueue ).getQueueSnapshot();
561                 will( returnValue( tasks ) );
562 
563                 exactly( 2 ).of( checkoutTaskQueueExecutor ).getCurrentTask();
564                 will( returnValue( null ) );
565 
566                 one( overallBuildQueue ).getName();
567                 will( returnValue( "BUILD_QUEUE_3" ) );
568             }
569         } );
570 
571         recordAddToCheckoutQueue();
572 
573         buildsManager.checkoutProject( 2, "continuum-project-test-2", new File( getBasedir(),
574                                                                                 "/target/test-working-dir/1" ), null,
575                                        "dummy", "dummypass", buildDef, null );
576         context.assertIsSatisfied();
577 
578         // queue third project - both queues have 1 task queued each; third project should be queued in 1st queue
579         recordStartOfCheckoutProjectSequence();
580 
581         context.checking( new Expectations()
582         {
583             {
584                 exactly( 2 ).of( checkoutQueue ).getQueueSnapshot();
585                 will( returnValue( tasksInFirstCheckoutQueue ) );
586 
587                 exactly( 2 ).of( checkoutTaskQueueExecutor ).getCurrentTask();
588                 will( returnValue( null ) );
589 
590                 one( overallBuildQueue ).getName();
591                 will( returnValue( "BUILD_QUEUE_2" ) );
592             }
593         } );
594 
595         recordAddToCheckoutQueue();
596 
597         buildsManager.checkoutProject( 3, "continuum-project-test-3", new File( getBasedir(),
598                                                                                 "/target/test-working-dir/1" ), null,
599                                        "dummy", "dummypass", buildDef, null );
600         context.assertIsSatisfied();
601     }
602 
603     public void testRemoveProjectFromCheckoutQueue()
604         throws Exception
605     {
606         setupMockOverallBuildQueues();
607 
608         context.checking( new Expectations()
609         {
610             {
611                 one( overallBuildQueue ).isInCheckoutQueue( 1 );
612                 will( returnValue( true ) );
613 
614                 one( overallBuildQueue ).removeProjectFromCheckoutQueue( 1 );
615             }
616         } );
617 
618         buildsManager.removeProjectFromCheckoutQueue( 1 );
619         context.assertIsSatisfied();
620     }
621 
622     public void testRemoveProjectsFromCheckoutQueue()
623         throws Exception
624     {
625         setupMockOverallBuildQueues();
626 
627         context.checking( new Expectations()
628         {
629             {
630                 exactly( 3 ).of( overallBuildQueue ).isInCheckoutQueue( with( any( int.class ) ) );
631                 will( returnValue( true ) );
632 
633                 exactly( 3 ).of( overallBuildQueue ).removeProjectFromCheckoutQueue( with( any( int.class ) ) );
634             }
635         } );
636 
637         int[] projectIds = new int[]{1, 2, 3};
638 
639         buildsManager.removeProjectsFromCheckoutQueue( projectIds );
640         context.assertIsSatisfied();
641     }
642 
643     public void testRemoveProjectFromCheckoutQueueProjectNotFound()
644         throws Exception
645     {
646         setupMockOverallBuildQueues();
647 
648         // shouldn't only the project's build queues be checked instead of all the overall build queues?
649         context.checking( new Expectations()
650         {
651             {
652                 exactly( 5 ).of( overallBuildQueue ).isInCheckoutQueue( 1 );
653                 will( returnValue( false ) );
654             }
655         } );
656 
657         buildsManager.removeProjectFromCheckoutQueue( 1 );
658         context.assertIsSatisfied();
659     }
660 
661     public void testRemoveDefaultOverallBuildQueue()
662         throws Exception
663     {
664         setupMockOverallBuildQueues();
665 
666         try
667         {
668             context.checking( new Expectations()
669             {
670                 {
671                     one( overallBuildQueue ).getName();
672                     will( returnValue( ConfigurationService.DEFAULT_BUILD_QUEUE_NAME ) );
673                 }
674             } );
675 
676             buildsManager.removeOverallBuildQueue( 1 );
677             context.assertIsSatisfied();
678             fail( "An exception should have been thrown." );
679         }
680         catch ( BuildManagerException e )
681         {
682             assertEquals( "Cannot remove default build queue.", e.getMessage() );
683         }
684     }
685 
686     public void testRemoveOverallBuildQueueNoTasksCurrentlyExecuting()
687         throws Exception
688     {
689         // queued tasks (both checkout & build tasks) must be transferred to the other queues!
690         setupMockOverallBuildQueues();
691 
692         final BuildDefinition buildDef = new BuildDefinition();
693         buildDef.setId( 1 );
694         buildDef.setSchedule( getSchedule( 1, 1, 2 ) );
695 
696         final TaskQueueExecutor buildQueueExecutor = context.mock( TaskQueueExecutor.class, "build-queue-executor" );
697         final TaskQueueExecutor checkoutQueueExecutor = context.mock( TaskQueueExecutor.class,
698                                                                       "checkout-queue-executor" );
699         final TaskQueueExecutor prepareBuildQueueExecutor = context.mock( TaskQueueExecutor.class,
700                                                                           "prepare-build-queue-executor" );
701 
702         final List<Task> buildTasks = new ArrayList<Task>();
703         buildTasks.add( new BuildProjectTask( 2, 1, new BuildTrigger( 1, "test-user" ), "continuum-project-test-2",
704                                               "BUILD_DEF", null, 2 ) );
705 
706         final List<CheckOutTask> checkoutTasks = new ArrayList<CheckOutTask>();
707         checkoutTasks.add( new CheckOutTask( 2, new File( getBasedir(), "/target/test-working-dir/1" ),
708                                              "continuum-project-test-2", "dummy", "dummypass", null, null ) );
709 
710         final List<Task> prepareBuildTasks = new ArrayList<Task>();
711         final Map<Integer, Integer> map = new HashMap<Integer, Integer>();
712         map.put( 1, 1 );
713         prepareBuildTasks.add( new PrepareBuildProjectsTask( map, new BuildTrigger( 1, "test-user" ), 1,
714                                                              "Project Group A", "http://scm.root.address", 2 ) );
715 
716         final ParallelBuildsThreadedTaskQueueExecutor buildTaskQueueExecutor = context.mock(
717             ParallelBuildsThreadedTaskQueueExecutor.class, "parallel-build-task-executor" );
718         final ParallelBuildsThreadedTaskQueueExecutor checkoutTaskQueueExecutor = context.mock(
719             ParallelBuildsThreadedTaskQueueExecutor.class, "parallel-checkout-task-executor" );
720         final ParallelBuildsThreadedTaskQueueExecutor prepareBuildTaskQueueExecutor = context.mock(
721             ParallelBuildsThreadedTaskQueueExecutor.class, "parallel-prepare-build-task-executor" );
722 
723         final List<Task> tasks = new ArrayList<Task>();
724 
725         context.checking( new Expectations()
726         {
727             {
728                 one( overallBuildQueue ).getName();
729                 will( returnValue( "BUILD_QUEUE_5" ) );
730 
731                 // check if there is any build task currently being executed
732                 one( overallBuildQueue ).getBuildTaskQueueExecutor();
733                 will( returnValue( buildQueueExecutor ) );
734                 one( buildQueueExecutor ).getCurrentTask();
735                 will( returnValue( null ) );
736                 //will( returnValue( buildTask ) );
737 
738                 // check if there is any checkout task currently being executed
739                 one( overallBuildQueue ).getCheckoutTaskQueueExecutor();
740                 will( returnValue( checkoutQueueExecutor ) );
741                 one( checkoutQueueExecutor ).getCurrentTask();
742                 will( returnValue( null ) );
743                 //will( returnValue( checkoutTask ) );
744 
745                 // check if there is any prepare build task currently being executed
746                 one( overallBuildQueue ).getPrepareBuildTaskQueueExecutor();
747                 will( returnValue( prepareBuildQueueExecutor ) );
748                 one( prepareBuildQueueExecutor ).getCurrentTask();
749                 will( returnValue( null ) );
750 
751                 // get all queued build tasks & remove them
752                 one( overallBuildQueue ).getProjectsInBuildQueue();
753                 will( returnValue( buildTasks ) );
754                 one( overallBuildQueue ).getBuildQueue();
755                 will( returnValue( buildQueue ) );
756                 one( buildQueue ).removeAll( buildTasks );
757 
758                 // get all queued checkout tasks & remove them
759                 one( overallBuildQueue ).getProjectsInCheckoutQueue();
760                 will( returnValue( checkoutTasks ) );
761                 one( overallBuildQueue ).getCheckoutQueue();
762                 will( returnValue( checkoutQueue ) );
763                 one( checkoutQueue ).removeAll( checkoutTasks );
764 
765                 // get all queued prepare build tasks & remove them
766                 one( overallBuildQueue ).getProjectsInPrepareBuildQueue();
767                 will( returnValue( prepareBuildTasks ) );
768                 one( overallBuildQueue ).getPrepareBuildQueue();
769                 will( returnValue( prepareBuildQueue ) );
770                 one( prepareBuildQueue ).removeAll( prepareBuildTasks );
771 
772                 // stop the build & checkout task queue executors
773                 one( overallBuildQueue ).getBuildTaskQueueExecutor();
774                 will( returnValue( buildTaskQueueExecutor ) );
775                 one( overallBuildQueue ).getCheckoutTaskQueueExecutor();
776                 will( returnValue( checkoutTaskQueueExecutor ) );
777                 one( overallBuildQueue ).getPrepareBuildTaskQueueExecutor();
778                 will( returnValue( prepareBuildTaskQueueExecutor ) );
779 
780                 one( buildTaskQueueExecutor ).stop();
781                 one( checkoutTaskQueueExecutor ).stop();
782                 one( prepareBuildTaskQueueExecutor ).stop();
783 
784                 // TODO: test scenario when there are no longer build queues configured aside from the one removed?
785                 //      - the behaviour should be that the default build queue will be used!
786 
787                 // re-queue projects in the build queue of the deleted overall build queue
788                 one( buildDefinitionDao ).getBuildDefinition( 1 );
789                 will( returnValue( buildDef ) );
790 
791                 // queue to other build queue
792                 exactly( 4 ).of( overallBuildQueue ).isInBuildQueue( with( any( int.class ) ) );
793                 will( returnValue( false ) );
794 
795                 exactly( 4 ).of( buildQueueExecutor ).getCurrentTask();
796                 will( returnValue( null ) );
797 
798                 one( projectDao ).getProjectsInGroup( with( any( int.class ) ) );
799                 will( returnValue( projects ) );
800 
801                 one( configurationService ).getNumberOfBuildsInParallel();
802                 will( returnValue( 2 ) );
803 
804                 exactly( 2 ).of( overallBuildQueue ).getBuildQueue();
805                 will( returnValue( buildQueue ) );
806 
807                 exactly( 6 ).of( overallBuildQueue ).getBuildTaskQueueExecutor();
808                 will( returnValue( buildQueueExecutor ) );
809 
810                 exactly( 2 ).of( buildQueue ).getQueueSnapshot();
811                 will( returnValue( tasks ) );
812 
813                 exactly( 2 ).of( buildQueueExecutor ).getCurrentTask();
814                 will( returnValue( null ) );
815 
816                 one( overallBuildQueue ).getName();
817                 will( returnValue( "BUILD_QUEUE_2" ) );
818 
819                 recordAddToBuildQueue();
820 
821                 // re-queue projects in the checkout queue of the deleted overall build queue
822                 one( buildDefinitionDao ).getDefaultBuildDefinition( 2 );
823                 will( returnValue( buildDef ) );
824 
825                 // queue to other checkout queues
826                 exactly( 4 ).of( overallBuildQueue ).isInCheckoutQueue( with( any( int.class ) ) );
827                 will( returnValue( false ) );
828 
829                 one( configurationService ).getNumberOfBuildsInParallel();
830                 will( returnValue( 2 ) );
831 
832                 exactly( 2 ).of( overallBuildQueue ).getCheckoutQueue();
833                 will( returnValue( checkoutQueue ) );
834 
835                 exactly( 2 ).of( overallBuildQueue ).getCheckoutTaskQueueExecutor();
836                 will( returnValue( checkoutQueueExecutor ) );
837 
838                 exactly( 2 ).of( checkoutQueue ).getQueueSnapshot();
839                 will( returnValue( tasks ) );
840 
841                 exactly( 2 ).of( checkoutQueueExecutor ).getCurrentTask();
842                 will( returnValue( null ) );
843 
844                 one( overallBuildQueue ).getName();
845                 will( returnValue( "BUILD_QUEUE_2" ) );
846 
847                 recordAddToCheckoutQueue();
848 
849                 // re-queue projects in the prepare build queue of the deleted overall build queue
850                 exactly( 4 ).of( overallBuildQueue ).isInPrepareBuildQueue( with( any( int.class ) ), with( any(
851                     int.class ) ) );
852                 will( returnValue( false ) );
853 
854                 one( buildDefinitionDao ).getBuildDefinition( 1 );
855                 will( returnValue( buildDef ) );
856 
857                 one( configurationService ).getNumberOfBuildsInParallel();
858                 will( returnValue( 2 ) );
859 
860                 exactly( 2 ).of( overallBuildQueue ).getPrepareBuildQueue();
861                 will( returnValue( prepareBuildQueue ) );
862 
863                 exactly( 2 ).of( overallBuildQueue ).getPrepareBuildTaskQueueExecutor();
864                 will( returnValue( prepareBuildQueueExecutor ) );
865 
866                 exactly( 2 ).of( prepareBuildQueue ).getQueueSnapshot();
867                 will( returnValue( tasks ) );
868 
869                 exactly( 2 ).of( prepareBuildQueueExecutor ).getCurrentTask();
870                 will( returnValue( null ) );
871 
872                 one( overallBuildQueue ).getName();
873                 will( returnValue( "BUILD_QUEUE_2" ) );
874 
875                 recordAddToPrepareBuildQueue();
876             }
877         } );
878 
879         buildsManager.removeOverallBuildQueue( 5 );
880         context.assertIsSatisfied();
881 
882         Map<Integer, OverallBuildQueue> overallBuildQueues = buildsManager.getOverallBuildQueues();
883         assertNull( overallBuildQueues.get( 5 ) );
884     }
885 
886     public void testRemoveOverallBuildQueueTasksCurrentlyExecuting()
887         throws Exception
888     {
889         setupMockOverallBuildQueues();
890 
891         final BuildDefinition buildDef = new BuildDefinition();
892         buildDef.setId( 1 );
893         buildDef.setSchedule( getSchedule( 1, 1, 2 ) );
894 
895         final TaskQueueExecutor buildQueueExecutor = context.mock( TaskQueueExecutor.class, "build-queue-executor" );
896         final Task buildTask = new BuildProjectTask( 1, 1, new BuildTrigger( 1, "test-user" ),
897                                                      "continuum-project-test-1", "BUILD_DEF", null, 1 );
898 
899         final List<BuildProjectTask> buildTasks = new ArrayList<BuildProjectTask>();
900         buildTasks.add( new BuildProjectTask( 2, 1, new BuildTrigger( 1, "test-user" ), "continuum-project-test-2",
901                                               "BUILD_DEF", null, 2 ) );
902 
903         final List<CheckOutTask> checkoutTasks = new ArrayList<CheckOutTask>();
904         checkoutTasks.add( new CheckOutTask( 2, new File( getBasedir(), "/target/test-working-dir/1" ),
905                                              "continuum-project-test-2", "dummy", "dummypass", null, null ) );
906 
907         try
908         {
909             context.checking( new Expectations()
910             {
911                 {
912                     one( overallBuildQueue ).getName();
913                     will( returnValue( "BUILD_QUEUE_5" ) );
914 
915                     // check if there is any build task currently being executed
916                     one( overallBuildQueue ).getBuildTaskQueueExecutor();
917                     will( returnValue( buildQueueExecutor ) );
918                     one( buildQueueExecutor ).getCurrentTask();
919                     will( returnValue( buildTask ) );
920                 }
921             } );
922 
923             buildsManager.removeOverallBuildQueue( 5 );
924             context.assertIsSatisfied();
925             fail( "An exception should have been thrown." );
926         }
927         catch ( BuildManagerException e )
928         {
929             assertEquals( "Cannot remove build queue. A task is currently executing.", e.getMessage() );
930         }
931     }
932 
933     public void testNoBuildQueuesConfigured()
934         throws Exception
935     {
936         overallBuildQueue = context.mock( OverallBuildQueue.class );
937 
938         Map<Integer, OverallBuildQueue> overallBuildQueues = Collections.synchronizedMap(
939             new HashMap<Integer, OverallBuildQueue>() );
940         overallBuildQueues.put( 1, overallBuildQueue );
941 
942         buildsManager.setOverallBuildQueues( overallBuildQueues );
943 
944         Schedule schedule = new Schedule();
945         schedule.setId( 1 );
946         schedule.setName( "DEFAULT_SCHEDULE" );
947         schedule.setCronExpression( "0 0 * * * ?" );
948         schedule.setDelay( 100 );
949         schedule.setMaxJobExecutionTime( 10000 );
950 
951         BuildDefinition buildDef = new BuildDefinition();
952         buildDef.setId( 1 );
953         buildDef.setSchedule( schedule );
954 
955         context.checking( new Expectations()
956         {
957             {
958                 one( overallBuildQueue ).isInBuildQueue( with( any( int.class ) ) );
959                 will( returnValue( false ) );
960 
961                 one( overallBuildQueue ).getBuildTaskQueueExecutor();
962                 will( returnValue( buildTaskQueueExecutor ) );
963 
964                 one( buildTaskQueueExecutor ).getCurrentTask();
965                 will( returnValue( null ) );
966 
967                 one( projectDao ).getProjectsInGroup( with( any( int.class ) ) );
968                 will( returnValue( projects ) );
969 
970                 one( configurationService ).getNumberOfBuildsInParallel();
971                 will( returnValue( 2 ) );
972 
973                 exactly( 2 ).of( overallBuildQueue ).getName();
974                 will( returnValue( ConfigurationService.DEFAULT_BUILD_QUEUE_NAME ) );
975 
976                 one( overallBuildQueue ).addToBuildQueue( with( any( BuildProjectTask.class ) ) );
977             }
978         } );
979 
980         buildsManager.buildProject( 1, buildDef, "continuum-project-test-1", new BuildTrigger( 1, "test-user" ), null,
981                                     1 );
982         context.assertIsSatisfied();
983     }
984 
985     public void testGetProjectsInBuildQueue()
986         throws Exception
987     {
988         setupMockOverallBuildQueues();
989 
990         final List<Task> tasks = new ArrayList<Task>();
991         tasks.add( new BuildProjectTask( 2, 1, new BuildTrigger( 1, "test-user" ), "continuum-project-test-2",
992                                          "BUILD_DEF", null, 2 ) );
993 
994         context.checking( new Expectations()
995         {
996             {
997                 exactly( 5 ).of( overallBuildQueue ).getName();
998                 will( returnValue( "BUILD_QUEUE" ) );
999 
1000                 exactly( 5 ).of( overallBuildQueue ).getProjectsInBuildQueue();
1001                 will( returnValue( tasks ) );
1002             }
1003         } );
1004 
1005         buildsManager.getProjectsInBuildQueues();
1006         context.assertIsSatisfied();
1007     }
1008 
1009     public void testGetProjectsInCheckoutQueue()
1010         throws Exception
1011     {
1012         setupMockOverallBuildQueues();
1013 
1014         final List<Task> tasks = new ArrayList<Task>();
1015         tasks.add( new CheckOutTask( 2, new File( getBasedir(), "/target/test-working-dir/1" ),
1016                                      "continuum-project-test-2", "dummy", "dummypass", null, null ) );
1017 
1018         context.checking( new Expectations()
1019         {
1020             {
1021                 exactly( 5 ).of( overallBuildQueue ).getName();
1022                 will( returnValue( "BUILD_QUEUE" ) );
1023 
1024                 exactly( 5 ).of( overallBuildQueue ).getProjectsInCheckoutQueue();
1025                 will( returnValue( tasks ) );
1026             }
1027         } );
1028 
1029         buildsManager.getProjectsInCheckoutQueues();
1030         context.assertIsSatisfied();
1031     }
1032 
1033     // prepare build queue
1034     public void testPrepareBuildProjectNoProjectQueuedInAnyOverallBuildQueues()
1035         throws Exception
1036     {
1037         setupMockOverallBuildQueues();
1038 
1039         Map<Integer, Integer> map = new HashMap<Integer, Integer>();
1040         map.put( 1, 1 );
1041 
1042         recordPrepareBuildProjectPrepareBuildQueuesAreEmpty();
1043 
1044         buildsManager.prepareBuildProjects( map, new BuildTrigger( 1, "test-user" ), 1, "Project Group A",
1045                                             "http://scm.root.address", 1 );
1046         context.assertIsSatisfied();
1047     }
1048 
1049     public void testPrepareBuildProjectsAlreadyQueued()
1050         throws Exception
1051     {
1052         setupMockOverallBuildQueues();
1053 
1054         Map<Integer, Integer> map = new HashMap<Integer, Integer>();
1055         map.put( 1, 1 );
1056 
1057         //queue second project - 1st queue is not empty, 2nd queue is empty 
1058         recordStartOfPrepareBuildProjectSequence();
1059 
1060         // the first prepare build queue already has a task queued
1061         final List<Task> tasks = new ArrayList<Task>();
1062         final List<Task> tasksOfFirstPrepareBuildQueue = new ArrayList<Task>();
1063         tasksOfFirstPrepareBuildQueue.add( new PrepareBuildProjectsTask( new HashMap<Integer, Integer>(),
1064                                                                          new BuildTrigger( 1, "test-user" ), 1,
1065                                                                          "Project Group B", "http://scm.root.address2",
1066                                                                          2 ) );
1067         context.checking( new Expectations()
1068         {
1069             {
1070                 one( prepareBuildQueue ).getQueueSnapshot();
1071                 will( returnValue( tasksOfFirstPrepareBuildQueue ) );
1072 
1073                 // the second prepare build queue has no tasks queued, so it should return 0
1074                 one( prepareBuildQueue ).getQueueSnapshot();
1075                 will( returnValue( tasks ) );
1076 
1077                 exactly( 2 ).of( prepareBuildTaskQueueExecutor ).getCurrentTask();
1078                 will( returnValue( null ) );
1079 
1080                 one( overallBuildQueue ).getName();
1081                 will( returnValue( "BUILD_QUEUE_3" ) );
1082             }
1083         } );
1084 
1085         recordAddToPrepareBuildQueue();
1086 
1087         buildsManager.prepareBuildProjects( map, new BuildTrigger( 1, "test-user" ), 1, "Project Group A",
1088                                             "http://scm.root.address", 1 );
1089         context.assertIsSatisfied();
1090 
1091         // queue third project - both queues have 1 task queued each
1092         recordStartOfPrepareBuildProjectSequence();
1093 
1094         // both queues have 1 task each        
1095         context.checking( new Expectations()
1096         {
1097             {
1098                 exactly( 2 ).of( prepareBuildQueue ).getQueueSnapshot();
1099                 will( returnValue( tasksOfFirstPrepareBuildQueue ) );
1100 
1101                 exactly( 2 ).of( prepareBuildTaskQueueExecutor ).getCurrentTask();
1102                 will( returnValue( null ) );
1103 
1104                 one( overallBuildQueue ).getName();
1105                 will( returnValue( "BUILD_QUEUE_2" ) );
1106             }
1107         } );
1108 
1109         recordAddToPrepareBuildQueue();
1110 
1111         buildsManager.prepareBuildProjects( map, new BuildTrigger( 1, "test-user" ), 1, "Project Group A",
1112                                             "http://scm.root.address", 1 );
1113         context.assertIsSatisfied();
1114     }
1115 
1116     public void testGetProjectsInPrepareBuildQueue()
1117         throws Exception
1118     {
1119         setupMockOverallBuildQueues();
1120 
1121         final List<Task> tasks = new ArrayList<Task>();
1122         tasks.add( new PrepareBuildProjectsTask( new HashMap<Integer, Integer>(), new BuildTrigger( 1, "test-user" ), 1,
1123                                                  "Project Group A", "http://scm.root.address", 2 ) );
1124 
1125         context.checking( new Expectations()
1126         {
1127             {
1128                 exactly( 5 ).of( overallBuildQueue ).getName();
1129                 will( returnValue( "PREPARE_BUILD_QUEUE" ) );
1130 
1131                 exactly( 5 ).of( overallBuildQueue ).getProjectsInPrepareBuildQueue();
1132                 will( returnValue( tasks ) );
1133             }
1134         } );
1135 
1136         buildsManager.getProjectsInPrepareBuildQueue();
1137         context.assertIsSatisfied();
1138     }
1139 
1140     public void testRemoveProjectFromPrepareBuildQueue()
1141         throws Exception
1142     {
1143         setupMockOverallBuildQueues();
1144         context.checking( new Expectations()
1145         {
1146             {
1147                 exactly( 5 ).of( overallBuildQueue ).isInPrepareBuildQueue( 1, 2 );
1148                 will( returnValue( true ) );
1149 
1150                 one( overallBuildQueue ).removeProjectFromPrepareBuildQueue( 1, 2 );
1151             }
1152         } );
1153 
1154         buildsManager.removeProjectFromPrepareBuildQueue( 1, 2 );
1155         context.assertIsSatisfied();
1156     }
1157 
1158     /*
1159     public void testNumOfAllowedParallelBuildsIsLessThanConfiguredBuildQueues()
1160         throws Exception
1161     {
1162     
1163     }
1164     
1165     public void testPrepareBuildProjects()
1166         throws Exception
1167     {
1168     
1169     }
1170     
1171     public void testRemoveProjectFromPrepareBuildQueue()
1172         throws Exception
1173     {
1174 
1175     }
1176     */
1177 }