View Javadoc
1   package org.apache.maven.lifecycle.internal.builder.multithreaded;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
5    * agreements. See the NOTICE file distributed with this work for additional information regarding
6    * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance with the License. You may obtain a
8    * copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software distributed under the License
13   * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
14   * or implied. See the License for the specific language governing permissions and limitations under
15   * the License.
16   */
17  
18  import junit.framework.TestCase;
19  
20  import org.apache.maven.execution.MavenSession;
21  import org.apache.maven.lifecycle.LifecycleNotFoundException;
22  import org.apache.maven.lifecycle.LifecyclePhaseNotFoundException;
23  import org.apache.maven.lifecycle.internal.ProjectBuildList;
24  import org.apache.maven.lifecycle.internal.ProjectSegment;
25  import org.apache.maven.lifecycle.internal.builder.multithreaded.ThreadOutputMuxer;
26  import org.apache.maven.lifecycle.internal.stub.ProjectDependencyGraphStub;
27  import org.apache.maven.plugin.InvalidPluginDescriptorException;
28  import org.apache.maven.plugin.MojoNotFoundException;
29  import org.apache.maven.plugin.PluginDescriptorParsingException;
30  import org.apache.maven.plugin.PluginNotFoundException;
31  import org.apache.maven.plugin.PluginResolutionException;
32  import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
33  import org.apache.maven.plugin.version.PluginVersionResolutionException;
34  
35  import java.io.ByteArrayOutputStream;
36  import java.io.PrintStream;
37  import java.util.ArrayList;
38  import java.util.Arrays;
39  import java.util.Iterator;
40  import java.util.List;
41  import java.util.concurrent.Callable;
42  import java.util.concurrent.CompletionService;
43  import java.util.concurrent.ExecutorCompletionService;
44  import java.util.concurrent.ExecutorService;
45  import java.util.concurrent.Executors;
46  import java.util.concurrent.Future;
47  
48  /**
49   * @author Kristian Rosenvold
50   */
51  public class ThreadOutputMuxerTest
52      extends TestCase
53  {
54  
55      final String paid = "Paid";
56  
57      final String in = "In";
58  
59      final String full = "Full";
60  
61      public void testSingleThreaded()
62          throws Exception
63      {
64          ProjectBuildList src = getProjectBuildList();
65          ProjectBuildList projectBuildList =
66              new ProjectBuildList( Arrays.asList( src.get( 0 ), src.get( 1 ), src.get( 2 ) ) );
67  
68          ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
69          PrintStream systemOut = new PrintStream( byteArrayOutputStream );
70          ThreadOutputMuxer threadOutputMuxer = new ThreadOutputMuxer( projectBuildList, systemOut );
71  
72          threadOutputMuxer.associateThreadWithProjectSegment( projectBuildList.get( 0 ) );
73          System.out.print( paid );  // No, this does not print to system.out. It's part of the test
74          assertEquals( paid.length(), byteArrayOutputStream.size() );
75          threadOutputMuxer.associateThreadWithProjectSegment( projectBuildList.get( 1 ) );
76          System.out.print( in );  // No, this does not print to system.out. It's part of the test
77          assertEquals( paid.length(), byteArrayOutputStream.size() );
78          threadOutputMuxer.associateThreadWithProjectSegment( projectBuildList.get( 2 ) );
79          System.out.print( full ); // No, this does not print to system.out. It's part of the test
80          assertEquals( paid.length(), byteArrayOutputStream.size() );
81  
82          threadOutputMuxer.setThisModuleComplete( projectBuildList.get( 0 ) );
83          threadOutputMuxer.setThisModuleComplete( projectBuildList.get( 1 ) );
84          threadOutputMuxer.setThisModuleComplete( projectBuildList.get( 2 ) );
85          threadOutputMuxer.close();
86          assertEquals( ( paid + in + full ).length(), byteArrayOutputStream.size() );
87      }
88  
89      public void testMultiThreaded()
90          throws Exception
91      {
92          ProjectBuildList projectBuildList = getProjectBuildList();
93  
94          ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
95          PrintStream systemOut = new PrintStream( byteArrayOutputStream );
96          final ThreadOutputMuxer threadOutputMuxer = new ThreadOutputMuxer( projectBuildList, systemOut );
97  
98          final List<String> stringList =
99              Arrays.asList( "Thinkin", "of", "a", "master", "plan", "Cuz", "ain’t", "nuthin", "but", "sweat", "inside",
100                            "my", "hand" );
101         Iterator<String> lyrics = stringList.iterator();
102 
103         ExecutorService executor = Executors.newFixedThreadPool( 10 );
104         CompletionService<ProjectSegment> service = new ExecutorCompletionService<>( executor );
105 
106         List<Future<ProjectSegment>> futures = new ArrayList<>();
107         for ( ProjectSegment projectBuild : projectBuildList )
108         {
109             final Future<ProjectSegment> buildFuture =
110                 service.submit( new Outputter( threadOutputMuxer, projectBuild, lyrics.next() ) );
111             futures.add( buildFuture );
112         }
113 
114         for ( Future<ProjectSegment> future : futures )
115         {
116             future.get();
117         }
118         int expectedLength = 0;
119         for ( int i = 0; i < projectBuildList.size(); i++ )
120         {
121             expectedLength += stringList.get( i ).length();
122         }
123 
124         threadOutputMuxer.close();
125         final byte[] bytes = byteArrayOutputStream.toByteArray();
126         String result = new String( bytes );
127         assertEquals( result, expectedLength, bytes.length );
128 
129 
130     }
131 
132     class Outputter
133         implements Callable<ProjectSegment>
134     {
135         private final ThreadOutputMuxer threadOutputMuxer;
136 
137         private final ProjectSegment item;
138 
139         private final String response;
140 
141         Outputter( ThreadOutputMuxer threadOutputMuxer, ProjectSegment item, String response )
142         {
143             this.threadOutputMuxer = threadOutputMuxer;
144             this.item = item;
145             this.response = response;
146         }
147 
148         public ProjectSegment call()
149             throws Exception
150         {
151             threadOutputMuxer.associateThreadWithProjectSegment( item );
152             System.out.print( response );
153             threadOutputMuxer.setThisModuleComplete( item );
154             return item;
155         }
156     }
157 
158 
159     private ProjectBuildList getProjectBuildList()
160         throws InvalidPluginDescriptorException, PluginVersionResolutionException, PluginDescriptorParsingException,
161         NoPluginFoundForPrefixException, MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
162         LifecyclePhaseNotFoundException, LifecycleNotFoundException
163     {
164         final MavenSession session = ProjectDependencyGraphStub.getMavenSession();
165         return ProjectDependencyGraphStub.getProjectBuildList( session );
166     }
167 }