/* * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. * 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.
*/
/* * @test * @requires vm.bits == 64 * @bug 8276766 * @summary Test jar --date source date of entries and that jars are * reproducible * @modules jdk.jartool * @run testng/othervm ReproducibleJar
*/
publicclass ReproducibleJar { privatestaticfinal ToolProvider JAR_TOOL = ToolProvider.findFirst("jar")
.orElseThrow(() -> new RuntimeException("jar tool not found")
);
// ZipEntry's mod date has 2 seconds precision: give extra time to // allow for e.g. rounding/truncation and networked/samba drives. privatestaticfinallong PRECISION = 10000L;
/** * Test jar tool with various valid --date <timestamps>
*/
@Test(dataProvider = "validSourceDates") publicvoid testValidSourceDate(String sourceDate) { if (isInTransition()) return;
// Test --date source date Assert.assertEquals(JAR_TOOL.run(System.out, System.err, "--create", "--file", JAR_FILE_SOURCE_DATE1.getName(), "--date", sourceDate,
DIR_OUTER.getName()), 0); Assert.assertTrue(JAR_FILE_SOURCE_DATE1.exists());
// Extract JAR_FILE_SOURCE_DATE1 and check last modified values Assert.assertEquals(JAR_TOOL.run(System.out, System.err, "--extract", "--file", JAR_FILE_SOURCE_DATE1.getName()), 0); Assert.assertTrue(DIR_OUTER.exists()); Assert.assertTrue(DIR_INNER.exists()); Assert.assertTrue(FILE_INNER.exists());
LocalDateTime expectedLdt = ZonedDateTime.parse(sourceDate,
DateTimeFormatter.ISO_DATE_TIME)
.withZoneSameInstant(ZoneOffset.UTC)
.toLocalDateTime();
System.out.format("Checking jar entries local date time for --date %s, is %s%n",
sourceDate, expectedLdt); long sourceDateEpochMillis = TimeUnit.MILLISECONDS.convert(
expectedLdt.toEpochSecond(ZoneId.systemDefault().getRules()
.getOffset(expectedLdt)), TimeUnit.SECONDS);
checkFileTime(DIR_OUTER.lastModified(), sourceDateEpochMillis);
checkFileTime(DIR_INNER.lastModified(), sourceDateEpochMillis);
checkFileTime(FILE_INNER.lastModified(), sourceDateEpochMillis);
}
/** * Test jar tool with various invalid --date <timestamps>
*/
@Test(dataProvider = "invalidSourceDates") publicvoid testInvalidSourceDate(String sourceDate) { // Negative Tests --date out of range or wrong format source date Assert.assertNotEquals(JAR_TOOL.run(System.out, System.err, "--create", "--file", JAR_FILE_SOURCE_DATE1.getName(), "--date", sourceDate,
DIR_OUTER.getName()), 0);
}
/** * Test jar produces deterministic reproducible output
*/
@Test(dataProvider = "validSourceDates") publicvoid testJarsReproducible(String sourceDate) throws IOException { // Test jars are reproducible across timezones
TimeZone tzAsia = TimeZone.getTimeZone("Asia/Shanghai");
TimeZone tzLA = TimeZone.getTimeZone("America/Los_Angeles");
TimeZone.setDefault(tzAsia); Assert.assertEquals(JAR_TOOL.run(System.out, System.err, "--create", "--file", JAR_FILE_SOURCE_DATE1.getName(), "--date", sourceDate,
DIR_OUTER.getName()), 0); Assert.assertTrue(JAR_FILE_SOURCE_DATE1.exists());
try { // Sleep 5 seconds to ensure jar timestamps might be different if they could be Thread.sleep(5000);
} catch (InterruptedException ex) {
}
// Check jars are identical Assert.assertEquals(Files.readAllBytes(JAR_FILE_SOURCE_DATE1.toPath()),
Files.readAllBytes(JAR_FILE_SOURCE_DATE2.toPath()));
}
/** * Create the standard directory structure used by the test: * outer/ * inner/ * foo.txt
*/ staticvoid createOuterInnerDirs() throws IOException { Assert.assertTrue(DIR_OUTER.mkdir()); Assert.assertTrue(DIR_INNER.mkdir()); try (PrintWriter pw = new PrintWriter(FILE_INNER)) {
pw.println("hello, world");
} Assert.assertTrue(DIR_OUTER.exists()); Assert.assertTrue(DIR_INNER.exists()); Assert.assertTrue(FILE_INNER.exists());
}
/** * Check the extracted and original millis since Epoch file times are * within the zip precision time period.
*/ staticvoid checkFileTime(long now, long original) { if (isTimeSettingChanged()) { return;
}
if (Math.abs(now - original) > PRECISION) { // If original time is after UNIX 2038 32bit rollover // and the now time is exactly the rollover time, then assume // running on a file system that only supports to 2038 (e.g.XFS) and pass test if (FileTime.fromMillis(original).toInstant().isAfter(UNIX_2038_ROLLOVER) &&
FileTime.fromMillis(now).toInstant().equals(UNIX_2038_ROLLOVER)) {
System.out.println("Checking file time after Unix 2038 rollover," + " and extracted file time is " + UNIX_2038_ROLLOVER_TIME + ", " + " Assuming restricted file system, pass file time check.");
} else { thrownew AssertionError("checkFileTime failed," + " extracted to " + FileTime.fromMillis(now) + ", expected to be close to " + FileTime.fromMillis(original));
}
}
}
/** * Has the timezone or DST changed during the test?
*/ privatestaticboolean isTimeSettingChanged() {
TimeZone currentTZ = TimeZone.getDefault(); boolean currentDST = currentTZ.inDaylightTime(new Date()); if (!currentTZ.equals(TZ) || currentDST != DST) {
System.out.println("Timezone or DST has changed during " + "ReproducibleJar testcase execution. Test skipped"); returntrue;
} else { returnfalse;
}
}
/** * Is the Zone currently within the transition change period?
*/ privatestaticboolean isInTransition() { var inTransition = false; var date = new Date(); var defZone = ZoneId.systemDefault(); if (defZone.getRules().getTransition(
date.toInstant().atZone(defZone).toLocalDateTime()) != null) {
System.out.println("ReproducibleJar testcase being run during Zone offset transition. Test skipped.");
inTransition = true;
} return inTransition;
}
/** * Remove the directory and its contents
*/ staticvoid cleanup(File dir) {
File[] x = dir.listFiles(); if (x != null) { for (File f : x) {
f.delete();
}
}
dir.delete();
}
}
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.