001    package org.apache.maven.lifecycle.internal;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
005     * agreements. See the NOTICE file distributed with this work for additional information regarding
006     * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance with the License. You may obtain a
008     * copy of the License at
009     *
010     * http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software distributed under the License
013     * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
014     * or implied. See the License for the specific language governing permissions and limitations under
015     * the License.
016     */
017    
018    import junit.framework.TestCase;
019    import org.apache.maven.execution.MavenSession;
020    import org.apache.maven.lifecycle.LifecycleNotFoundException;
021    import org.apache.maven.lifecycle.LifecyclePhaseNotFoundException;
022    import org.apache.maven.lifecycle.internal.stub.ProjectDependencyGraphStub;
023    import org.apache.maven.plugin.InvalidPluginDescriptorException;
024    import org.apache.maven.plugin.MojoNotFoundException;
025    import org.apache.maven.plugin.PluginDescriptorParsingException;
026    import org.apache.maven.plugin.PluginNotFoundException;
027    import org.apache.maven.plugin.PluginResolutionException;
028    import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
029    import org.apache.maven.plugin.version.PluginVersionResolutionException;
030    
031    import java.io.ByteArrayOutputStream;
032    import java.io.PrintStream;
033    import java.util.ArrayList;
034    import java.util.Arrays;
035    import java.util.Iterator;
036    import java.util.List;
037    import java.util.concurrent.Callable;
038    import java.util.concurrent.CompletionService;
039    import java.util.concurrent.ExecutorCompletionService;
040    import java.util.concurrent.ExecutorService;
041    import java.util.concurrent.Executors;
042    import java.util.concurrent.Future;
043    
044    /**
045     * @author Kristian Rosenvold
046     */
047    public class ThreadOutputMuxerTest
048        extends TestCase
049    {
050    
051        final String paid = "Paid";
052    
053        final String in = "In";
054    
055        final String full = "Full";
056    
057        public void testSingleThreaded()
058            throws Exception
059        {
060            ProjectBuildList src = getProjectBuildList();
061            ProjectBuildList projectBuildList =
062                new ProjectBuildList( Arrays.asList( src.get( 0 ), src.get( 1 ), src.get( 2 ) ) );
063    
064            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
065            PrintStream systemOut = new PrintStream( byteArrayOutputStream );
066            ThreadOutputMuxer threadOutputMuxer = new ThreadOutputMuxer( projectBuildList, systemOut );
067    
068            threadOutputMuxer.associateThreadWithProjectSegment( projectBuildList.get( 0 ) );
069            System.out.print( paid );  // No, this does not print to system.out. It's part of the test
070            assertEquals( paid.length(), byteArrayOutputStream.size() );
071            threadOutputMuxer.associateThreadWithProjectSegment( projectBuildList.get( 1 ) );
072            System.out.print( in );  // No, this does not print to system.out. It's part of the test
073            assertEquals( paid.length(), byteArrayOutputStream.size() );
074            threadOutputMuxer.associateThreadWithProjectSegment( projectBuildList.get( 2 ) );
075            System.out.print( full ); // No, this does not print to system.out. It's part of the test
076            assertEquals( paid.length(), byteArrayOutputStream.size() );
077    
078            threadOutputMuxer.setThisModuleComplete( projectBuildList.get( 0 ) );
079            threadOutputMuxer.setThisModuleComplete( projectBuildList.get( 1 ) );
080            threadOutputMuxer.setThisModuleComplete( projectBuildList.get( 2 ) );
081            threadOutputMuxer.close();
082            assertEquals( ( paid + in + full ).length(), byteArrayOutputStream.size() );
083        }
084    
085        public void testMultiThreaded()
086            throws Exception
087        {
088            ProjectBuildList projectBuildList = getProjectBuildList();
089    
090            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
091            PrintStream systemOut = new PrintStream( byteArrayOutputStream );
092            final ThreadOutputMuxer threadOutputMuxer = new ThreadOutputMuxer( projectBuildList, systemOut );
093    
094            final List<String> stringList =
095                Arrays.asList( "Thinkin", "of", "a", "master", "plan", "Cuz", "ain’t", "nuthin", "but", "sweat", "inside",
096                               "my", "hand" );
097            Iterator<String> lyrics = stringList.iterator();
098    
099            ExecutorService executor = Executors.newFixedThreadPool( 10 );
100            CompletionService<ProjectSegment> service = new ExecutorCompletionService<ProjectSegment>( executor );
101    
102            List<Future<ProjectSegment>> futures = new ArrayList<Future<ProjectSegment>>();
103            for ( ProjectSegment projectBuild : projectBuildList )
104            {
105                final Future<ProjectSegment> buildFuture =
106                    service.submit( new Outputter( threadOutputMuxer, projectBuild, lyrics.next() ) );
107                futures.add( buildFuture );
108            }
109    
110            for ( Future<ProjectSegment> future : futures )
111            {
112                future.get();
113            }
114            int expectedLength = 0;
115            for ( int i = 0; i < projectBuildList.size(); i++ )
116            {
117                expectedLength += stringList.get( i ).length();
118            }
119    
120            threadOutputMuxer.close();
121            final byte[] bytes = byteArrayOutputStream.toByteArray();
122            String result = new String( bytes );
123            assertEquals( result, expectedLength, bytes.length );
124    
125    
126        }
127    
128        class Outputter
129            implements Callable<ProjectSegment>
130        {
131            private final ThreadOutputMuxer threadOutputMuxer;
132    
133            private final ProjectSegment item;
134    
135            private final String response;
136    
137            Outputter( ThreadOutputMuxer threadOutputMuxer, ProjectSegment item, String response )
138            {
139                this.threadOutputMuxer = threadOutputMuxer;
140                this.item = item;
141                this.response = response;
142            }
143    
144            public ProjectSegment call()
145                throws Exception
146            {
147                threadOutputMuxer.associateThreadWithProjectSegment( item );
148                System.out.print( response );
149                threadOutputMuxer.setThisModuleComplete( item );
150                return item;
151            }
152        }
153    
154    
155        private ProjectBuildList getProjectBuildList()
156            throws InvalidPluginDescriptorException, PluginVersionResolutionException, PluginDescriptorParsingException,
157            NoPluginFoundForPrefixException, MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
158            LifecyclePhaseNotFoundException, LifecycleNotFoundException
159        {
160            final MavenSession session = ProjectDependencyGraphStub.getMavenSession();
161            return ProjectDependencyGraphStub.getProjectBuildList( session );
162        }
163    }