2024-11-11 13:35:25 +00:00
/ *
* Copyright ( c ) 2024 , Red Hat , Inc .
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER .
*
* This code is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License version 2 only , as
* published by the Free Software Foundation .
*
* This code is distributed in the hope that it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License
* version 2 for more details ( a copy is included in the LICENSE file that
* accompanied this code ) .
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work ; if not , write to the Free Software Foundation ,
* Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA .
*
* Please contact Oracle , 500 Oracle Parkway , Redwood Shores , CA 94065 USA
* or visit www . oracle . com if you need additional information or have any
* questions .
* /
import java.io.IOException ;
import java.nio.file.FileVisitResult ;
import java.nio.file.Files ;
import java.nio.file.Path ;
import java.nio.file.SimpleFileVisitor ;
import java.nio.file.attribute.BasicFileAttributes ;
import java.util.ArrayList ;
import java.util.Arrays ;
import java.util.Collections ;
import java.util.List ;
import tests.Helper ;
import tests.JImageGenerator ;
/ *
* @test
* @summary Compare packaged - modules jlink with a run - time image based jlink to
* produce the same result
* @requires ( jlink . packagedModules & vm . compMode ! = " Xcomp " & os . maxMemory > = 2g )
* @library . . / . . / lib / test / lib
* @enablePreview
* @modules java . base / jdk . internal . jimage
* jdk . jlink / jdk . tools . jlink . internal
* jdk . jlink / jdk . tools . jlink . plugin
* jdk . jlink / jdk . tools . jimage
* @build tests . * jdk . test . lib . process . OutputAnalyzer
* jdk . test . lib . process . ProcessTools
2024-11-19 13:44:11 +00:00
* @run main / othervm / timeout = 1200 - Xmx1400m PackagedModulesVsRuntimeImageLinkTest
2024-11-11 13:35:25 +00:00
* /
public class PackagedModulesVsRuntimeImageLinkTest extends AbstractLinkableRuntimeTest {
public static void main ( String [ ] args ) throws Exception {
PackagedModulesVsRuntimeImageLinkTest test = new PackagedModulesVsRuntimeImageLinkTest ( ) ;
test . run ( ) ;
}
@Override
void runTest ( Helper helper , boolean isLinkableRuntime ) throws Exception {
// create a java.se using jmod-less approach
BaseJlinkSpecBuilder builder = new BaseJlinkSpecBuilder ( )
. helper ( helper )
. name ( " java-se-jmodless " )
. addModule ( " java.se " )
. validatingModule ( " java.se " ) ;
if ( isLinkableRuntime ) {
builder . setLinkableRuntime ( ) ;
}
Path javaSEruntimeLink = createJavaImageRuntimeLink ( builder . build ( ) ) ;
// create a java.se using packaged modules (jmod-full)
Path javaSEJmodFull = JImageGenerator . getJLinkTask ( )
. output ( helper . createNewImageDir ( " java-se-jmodfull " ) )
. addMods ( " java.se " ) . call ( ) . assertSuccess ( ) ;
2024-11-19 13:44:11 +00:00
System . out . println ( " Now comparing jmod-less and jmod-full) images " ) ;
2024-11-11 13:35:25 +00:00
compareRecursively ( javaSEruntimeLink , javaSEJmodFull ) ;
}
// Visit all files in the given directories checking that they're byte-by-byte identical
private static void compareRecursively ( Path javaSEJmodLess ,
Path javaSEJmodFull ) throws IOException , AssertionError {
FilesCapturingVisitor jmodFullVisitor = new FilesCapturingVisitor ( javaSEJmodFull ) ;
FilesCapturingVisitor jmodLessVisitor = new FilesCapturingVisitor ( javaSEJmodLess ) ;
Files . walkFileTree ( javaSEJmodFull , jmodFullVisitor ) ;
Files . walkFileTree ( javaSEJmodLess , jmodLessVisitor ) ;
List < String > jmodFullFiles = jmodFullVisitor . filesVisited ( ) ;
List < String > jmodLessFiles = jmodLessVisitor . filesVisited ( ) ;
Collections . sort ( jmodFullFiles ) ;
Collections . sort ( jmodLessFiles ) ;
if ( jmodFullFiles . size ( ) ! = jmodLessFiles . size ( ) ) {
throw new AssertionError ( String . format ( " Size of files different for jmod-less (%d) vs jmod-full (%d) java.se jlink " , jmodLessFiles . size ( ) , jmodFullFiles . size ( ) ) ) ;
}
String jimageFile = Path . of ( " lib " ) . resolve ( " modules " ) . toString ( ) ;
// Compare all files except the modules image
for ( int i = 0 ; i < jmodFullFiles . size ( ) ; i + + ) {
String jmodFullPath = jmodFullFiles . get ( i ) ;
String jmodLessPath = jmodLessFiles . get ( i ) ;
if ( ! jmodFullPath . equals ( jmodLessPath ) ) {
throw new AssertionError ( String . format ( " jmod-full path (%s) != jmod-less path (%s) " , jmodFullPath , jmodLessPath ) ) ;
}
if ( jmodFullPath . equals ( jimageFile ) ) {
continue ;
}
Path a = javaSEJmodFull . resolve ( Path . of ( jmodFullPath ) ) ;
Path b = javaSEJmodLess . resolve ( Path . of ( jmodLessPath ) ) ;
if ( Files . mismatch ( a , b ) ! = - 1L ) {
handleFileMismatch ( a , b ) ;
}
}
// Compare jimage contents by iterating its entries and comparing their
// paths and content bytes
//
// Note: The files aren't byte-by-byte comparable (probably due to string hashing
// and offset differences in container bytes)
Path jimageJmodLess = javaSEJmodLess . resolve ( Path . of ( " lib " ) ) . resolve ( Path . of ( " modules " ) ) ;
Path jimageJmodFull = javaSEJmodFull . resolve ( Path . of ( " lib " ) ) . resolve ( Path . of ( " modules " ) ) ;
List < String > jimageContentJmodLess = JImageHelper . listContents ( jimageJmodLess ) ;
List < String > jimageContentJmodFull = JImageHelper . listContents ( jimageJmodFull ) ;
if ( jimageContentJmodLess . size ( ) ! = jimageContentJmodFull . size ( ) ) {
throw new AssertionError ( String . format ( " Size of jimage content differs for jmod-less (%d) v. jmod-full (%d) " , jimageContentJmodLess . size ( ) , jimageContentJmodFull . size ( ) ) ) ;
}
for ( int i = 0 ; i < jimageContentJmodFull . size ( ) ; i + + ) {
if ( ! jimageContentJmodFull . get ( i ) . equals ( jimageContentJmodLess . get ( i ) ) ) {
throw new AssertionError ( String . format ( " Jimage content differs at index %d: jmod-full was: '%s' jmod-less was: '%s' " ,
i ,
jimageContentJmodFull . get ( i ) ,
jimageContentJmodLess . get ( i )
) ) ;
}
String loc = jimageContentJmodFull . get ( i ) ;
if ( isTreeInfoResource ( loc ) ) {
// Skip container bytes as those are offsets to the content
// of the container which might be different between jlink runs.
continue ;
}
byte [ ] resBytesFull = JImageHelper . getLocationBytes ( loc , jimageJmodFull ) ;
byte [ ] resBytesLess = JImageHelper . getLocationBytes ( loc , jimageJmodLess ) ;
if ( resBytesFull . length ! = resBytesLess . length | | Arrays . mismatch ( resBytesFull , resBytesLess ) ! = - 1 ) {
throw new AssertionError ( " Content bytes mismatch for " + loc ) ;
}
}
}
private static boolean isTreeInfoResource ( String path ) {
return path . startsWith ( " /packages " ) | | path . startsWith ( " /modules " ) ;
}
private static void handleFileMismatch ( Path a , Path b ) {
throw new AssertionError ( " Files mismatch: " + a + " vs. " + b ) ;
}
static class FilesCapturingVisitor extends SimpleFileVisitor < Path > {
private final Path basePath ;
private final List < String > filePaths = new ArrayList < > ( ) ;
public FilesCapturingVisitor ( Path basePath ) {
this . basePath = basePath ;
}
@Override
public FileVisitResult visitFile ( Path path , BasicFileAttributes attrs ) {
Path relative = basePath . relativize ( path ) ;
filePaths . add ( relative . toString ( ) ) ;
return FileVisitResult . CONTINUE ;
}
List < String > filesVisited ( ) {
return filePaths ;
}
}
}