001package org.apache.maven.lifecycle.internal.builder.multithreaded; 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 018import junit.framework.TestCase; 019 020import org.apache.maven.execution.MavenSession; 021import org.apache.maven.lifecycle.LifecycleNotFoundException; 022import org.apache.maven.lifecycle.LifecyclePhaseNotFoundException; 023import org.apache.maven.lifecycle.internal.ProjectBuildList; 024import org.apache.maven.lifecycle.internal.ProjectSegment; 025import org.apache.maven.lifecycle.internal.builder.multithreaded.ThreadOutputMuxer; 026import org.apache.maven.lifecycle.internal.stub.ProjectDependencyGraphStub; 027import org.apache.maven.plugin.InvalidPluginDescriptorException; 028import org.apache.maven.plugin.MojoNotFoundException; 029import org.apache.maven.plugin.PluginDescriptorParsingException; 030import org.apache.maven.plugin.PluginNotFoundException; 031import org.apache.maven.plugin.PluginResolutionException; 032import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException; 033import org.apache.maven.plugin.version.PluginVersionResolutionException; 034 035import java.io.ByteArrayOutputStream; 036import java.io.PrintStream; 037import java.util.ArrayList; 038import java.util.Arrays; 039import java.util.Iterator; 040import java.util.List; 041import java.util.concurrent.Callable; 042import java.util.concurrent.CompletionService; 043import java.util.concurrent.ExecutorCompletionService; 044import java.util.concurrent.ExecutorService; 045import java.util.concurrent.Executors; 046import java.util.concurrent.Future; 047 048/** 049 * @author Kristian Rosenvold 050 */ 051public class ThreadOutputMuxerTest 052 extends TestCase 053{ 054 055 final String paid = "Paid"; 056 057 final String in = "In"; 058 059 final String full = "Full"; 060 061 public void testSingleThreaded() 062 throws Exception 063 { 064 ProjectBuildList src = getProjectBuildList(); 065 ProjectBuildList projectBuildList = 066 new ProjectBuildList( Arrays.asList( src.get( 0 ), src.get( 1 ), src.get( 2 ) ) ); 067 068 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 069 PrintStream systemOut = new PrintStream( byteArrayOutputStream ); 070 ThreadOutputMuxer threadOutputMuxer = new ThreadOutputMuxer( projectBuildList, systemOut ); 071 072 threadOutputMuxer.associateThreadWithProjectSegment( projectBuildList.get( 0 ) ); 073 System.out.print( paid ); // No, this does not print to system.out. It's part of the test 074 assertEquals( paid.length(), byteArrayOutputStream.size() ); 075 threadOutputMuxer.associateThreadWithProjectSegment( projectBuildList.get( 1 ) ); 076 System.out.print( in ); // No, this does not print to system.out. It's part of the test 077 assertEquals( paid.length(), byteArrayOutputStream.size() ); 078 threadOutputMuxer.associateThreadWithProjectSegment( projectBuildList.get( 2 ) ); 079 System.out.print( full ); // No, this does not print to system.out. It's part of the test 080 assertEquals( paid.length(), byteArrayOutputStream.size() ); 081 082 threadOutputMuxer.setThisModuleComplete( projectBuildList.get( 0 ) ); 083 threadOutputMuxer.setThisModuleComplete( projectBuildList.get( 1 ) ); 084 threadOutputMuxer.setThisModuleComplete( projectBuildList.get( 2 ) ); 085 threadOutputMuxer.close(); 086 assertEquals( ( paid + in + full ).length(), byteArrayOutputStream.size() ); 087 } 088 089 public void testMultiThreaded() 090 throws Exception 091 { 092 ProjectBuildList projectBuildList = getProjectBuildList(); 093 094 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 095 PrintStream systemOut = new PrintStream( byteArrayOutputStream ); 096 final ThreadOutputMuxer threadOutputMuxer = new ThreadOutputMuxer( projectBuildList, systemOut ); 097 098 final List<String> stringList = 099 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<ProjectSegment>( executor ); 105 106 List<Future<ProjectSegment>> futures = new ArrayList<Future<ProjectSegment>>(); 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}