diff --git a/.github/actions/do-build/action.yml b/.github/actions/do-build/action.yml index 3deb7f4b8f8..79eddf8c70f 100644 --- a/.github/actions/do-build/action.yml +++ b/.github/actions/do-build/action.yml @@ -66,7 +66,7 @@ runs: shell: bash - name: 'Upload build logs' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: failure-logs-${{ inputs.platform }}${{ inputs.debug-suffix }} path: failure-logs @@ -74,7 +74,7 @@ runs: # This is the best way I found to abort the job with an error message - name: 'Notify about build failures' - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: core.setFailed('Build failed. See summary for details.') if: steps.check.outputs.failure == 'true' diff --git a/.github/actions/get-bootjdk/action.yml b/.github/actions/get-bootjdk/action.yml index 1e569dd47c5..25ee1d8dfa0 100644 --- a/.github/actions/get-bootjdk/action.yml +++ b/.github/actions/get-bootjdk/action.yml @@ -65,7 +65,7 @@ runs: - name: 'Check cache for BootJDK' id: get-cached-bootjdk - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: bootjdk/jdk key: boot-jdk-${{ inputs.platform }}-${{ steps.sha256.outputs.value }} diff --git a/.github/actions/get-bundles/action.yml b/.github/actions/get-bundles/action.yml index 956e1520cfb..0e52320a350 100644 --- a/.github/actions/get-bundles/action.yml +++ b/.github/actions/get-bundles/action.yml @@ -48,14 +48,14 @@ runs: steps: - name: 'Download bundles artifact' id: download-bundles - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: bundles-${{ inputs.platform }}${{ inputs.debug-suffix }} path: bundles continue-on-error: true - name: 'Download bundles artifact (retry)' - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: bundles-${{ inputs.platform }}${{ inputs.debug-suffix }} path: bundles diff --git a/.github/actions/get-jtreg/action.yml b/.github/actions/get-jtreg/action.yml index 596f5058191..b5ea884c7ec 100644 --- a/.github/actions/get-jtreg/action.yml +++ b/.github/actions/get-jtreg/action.yml @@ -41,7 +41,7 @@ runs: - name: 'Check cache for JTReg' id: get-cached-jtreg - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: jtreg/installed key: jtreg-${{ steps.version.outputs.value }} diff --git a/.github/actions/get-msys2/action.yml b/.github/actions/get-msys2/action.yml index f6de676a327..843b77ac064 100644 --- a/.github/actions/get-msys2/action.yml +++ b/.github/actions/get-msys2/action.yml @@ -30,7 +30,7 @@ runs: using: composite steps: - name: 'Install MSYS2' - uses: msys2/setup-msys2@v2 + uses: msys2/setup-msys2@v2.22.0 with: install: 'autoconf tar unzip zip make' path-type: minimal diff --git a/.github/actions/upload-bundles/action.yml b/.github/actions/upload-bundles/action.yml index 88f7f6e8107..b35ee3a42e9 100644 --- a/.github/actions/upload-bundles/action.yml +++ b/.github/actions/upload-bundles/action.yml @@ -69,7 +69,7 @@ runs: shell: bash - name: 'Upload bundles artifact' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: bundles-${{ inputs.platform }}${{ inputs.debug-suffix }} path: bundles diff --git a/.github/workflows/build-cross-compile.yml b/.github/workflows/build-cross-compile.yml index 88251fded11..385b097b9fc 100644 --- a/.github/workflows/build-cross-compile.yml +++ b/.github/workflows/build-cross-compile.yml @@ -87,13 +87,6 @@ jobs: with: platform: linux-x64 - # Use linux-x64 JDK bundle as build JDK - - name: 'Get build JDK' - id: buildjdk - uses: ./.github/actions/get-bundles - with: - platform: linux-x64 - # Upgrading apt to solve libc6 installation bugs, see JDK-8260460. - name: 'Install toolchain and dependencies' run: | @@ -110,7 +103,7 @@ jobs: - name: 'Check cache for sysroot' id: get-cached-sysroot - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: sysroot key: sysroot-${{ matrix.debian-arch }}-${{ hashFiles('./.github/workflows/build-cross-compile.yml') }} @@ -154,7 +147,6 @@ jobs: --disable-precompiled-headers --openjdk-target=${{ matrix.gnu-arch }}-linux-gnu${{ matrix.gnu-abi}} --with-sysroot=sysroot - --with-build-jdk=${{ steps.buildjdk.outputs.jdk-path }} CC=${{ matrix.gnu-arch }}-linux-gnu${{ matrix.gnu-abi}}-gcc-${{ inputs.gcc-major-version }} CXX=${{ matrix.gnu-arch }}-linux-gnu${{ matrix.gnu-abi}}-g++-${{ inputs.gcc-major-version }} ${{ inputs.extra-conf-options }} ${{ inputs.configure-arguments }} || ( diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 32a0f7f229e..dca1a9ae4fa 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -65,7 +65,53 @@ jobs: build-linux-x64: name: linux-x64 +<<<<<<< HEAD needs: prerequisites +======= + needs: select + uses: ./.github/workflows/build-linux.yml + with: + platform: linux-x64 + gcc-major-version: '10' + configure-arguments: ${{ github.event.inputs.configure-arguments }} + make-arguments: ${{ github.event.inputs.make-arguments }} + if: needs.select.outputs.linux-x64 == 'true' + + build-linux-x86: + name: linux-x86 + needs: select + uses: ./.github/workflows/build-linux.yml + with: + platform: linux-x86 + gcc-major-version: '10' + gcc-package-suffix: '-multilib' + apt-architecture: 'i386' + # Some multilib libraries do not have proper inter-dependencies, so we have to + # install their dependencies manually. + apt-extra-packages: 'libfreetype-dev:i386 libtiff-dev:i386 libcupsimage2-dev:i386' + extra-conf-options: '--with-target-bits=32' + configure-arguments: ${{ github.event.inputs.configure-arguments }} + make-arguments: ${{ github.event.inputs.make-arguments }} + if: needs.select.outputs.linux-x86 == 'true' + + build-linux-x64-hs-nopch: + name: linux-x64-hs-nopch + needs: select + uses: ./.github/workflows/build-linux.yml + with: + platform: linux-x64 + make-target: 'hotspot' + debug-levels: '[ "debug" ]' + gcc-major-version: '10' + extra-conf-options: '--disable-precompiled-headers' + configure-arguments: ${{ github.event.inputs.configure-arguments }} + make-arguments: ${{ github.event.inputs.make-arguments }} + if: needs.select.outputs.linux-x64-variants == 'true' + + build-linux-x64-hs-zero: + name: linux-x64-hs-zero + needs: select +>>>>>>> jdk-11.0.24+8 uses: ./.github/workflows/build-linux.yml with: platform: linux-x64 @@ -82,7 +128,26 @@ jobs: needs: prerequisites uses: ./.github/workflows/build-linux.yml with: +<<<<<<< HEAD platform: linux-aarch64 +======= + platform: linux-x64 + make-target: 'hotspot' + # Technically this is not the "debug" level, but we can't inject a new matrix state for just this job + debug-levels: '[ "debug" ]' + gcc-major-version: '10' + extra-conf-options: '--with-debug-level=optimized --disable-precompiled-headers' + configure-arguments: ${{ github.event.inputs.configure-arguments }} + make-arguments: ${{ github.event.inputs.make-arguments }} + if: needs.select.outputs.linux-x64-variants == 'true' + + build-linux-cross-compile: + name: linux-cross-compile + needs: + - select + uses: ./.github/workflows/build-cross-compile.yml + with: +>>>>>>> jdk-11.0.24+8 gcc-major-version: '10' configure-arguments: ${{ github.event.inputs.configure-arguments }} make-arguments: ${{ github.event.inputs.make-arguments }} @@ -169,7 +234,7 @@ jobs: # Hack to get hold of the api environment variables that are only defined for actions - name: 'Get API configuration' id: api - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: 'return { url: process.env["ACTIONS_RUNTIME_URL"], token: process.env["ACTIONS_RUNTIME_TOKEN"] }' diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 48009e8509d..2b76a44a153 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -228,7 +228,7 @@ jobs: if: steps.check_if_run.outputs.should_run != 'false' - name: 'Upload test results' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: path: results name: ${{ steps.package.outputs.artifact-name }} @@ -236,7 +236,7 @@ jobs: # This is the best way I found to abort the job with an error message - name: 'Notify about test failures' - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: core.setFailed('${{ steps.run-tests.outputs.error-message }}') if: steps.run-tests.outputs.failure == 'true' && steps.check_if_run.outputs.should_run != 'false' diff --git a/.jcheck/conf b/.jcheck/conf index 2ca83defe29..be7ad6d26f5 100644 --- a/.jcheck/conf +++ b/.jcheck/conf @@ -1,7 +1,7 @@ [general] project=jdk-updates jbs=JDK -version=11.0.23 +version=11.0.24 [checks] error=author,committer,reviewers,merge,issues,executable,symlink,message,hg-tag,whitespace diff --git a/doc/testing.html b/doc/testing.html index 18ba3e2baf6..c3e8ca956b0 100644 --- a/doc/testing.html +++ b/doc/testing.html @@ -5,7 +5,7 @@ Testing the JDK - " + + "
  1. wwwww
"; + + mainFrame = new JFrame("bug4476002"); + + htmlComponent = new JLabel(htmlText); + mainFrame.getContentPane().add(htmlComponent); + + mainFrame.pack(); + mainFrame.setLocationRelativeTo(null); + mainFrame.setVisible(true); + }); + robot.waitForIdle(); + robot.delay(1000); + SwingUtilities.invokeAndWait(() -> { + p = htmlComponent.getLocationOnScreen(); + d = htmlComponent.getSize(); + }); + int x0 = p.x; + int y = p.y + d.height/2; + + for (int x = x0; x < x0 + d.width; x++) { + if (robot.getPixelColor(x, y).equals(Color.black)) { + passed = false; + break; + } + } + if (!passed) { + throw new RuntimeException("Test failed."); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (mainFrame != null) { + mainFrame.dispose(); + } + }); + } + } + +} diff --git a/test/jdk/javax/swing/text/html/TableView/bug4412522.java b/test/jdk/javax/swing/text/html/TableView/bug4412522.java new file mode 100644 index 00000000000..f983b07ecfc --- /dev/null +++ b/test/jdk/javax/swing/text/html/TableView/bug4412522.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2003, 2023, 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 + * @bug 4412522 + * @summary Tests if HTML that has comments inside of tables is rendered correctly + * @key headful + * @run main bug4412522 +*/ + +import javax.swing.JEditorPane; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; +import javax.swing.text.View; +import javax.swing.text.html.HTMLEditorKit; + +import java.awt.Robot; +import java.awt.Shape; + +public class bug4412522 { + + private static boolean passed = false; + + private static JEditorPane jep; + private static JFrame f; + private static Robot robot; + + public void init() { + + String text = + "" + + "" + + "" + + "
first cellsecond cell
row heading
"; + + JFrame f = new JFrame(); + jep = new JEditorPane(); + jep.setEditorKit(new HTMLEditorKit()); + jep.setEditable(false); + + jep.setText(text); + + f.getContentPane().add(jep); + f.setSize(500,500); + f.setLocationRelativeTo(null); + f.setVisible(true); + } + + + public static void main(String args[]) throws Exception { + robot = new Robot(); + robot.setAutoDelay(100); + bug4412522 test = new bug4412522(); + try { + SwingUtilities.invokeAndWait(() -> test.init()); + robot.waitForIdle(); + robot.delay(1000); + Shape r = jep.getBounds(); + View v = jep.getUI().getRootView(jep); + int tableWidth = 0; + int cellsWidth = 0; + + while (!(v instanceof javax.swing.text.html.ParagraphView)) { + + int n = v.getViewCount(); + Shape sh = v.getChildAllocation(n - 1, r); + String viewName = v.getClass().getName(); + if (viewName.endsWith("TableView")) { + tableWidth = r.getBounds().width; + } + + if (viewName.endsWith("CellView")) { + cellsWidth = r.getBounds().x + r.getBounds().width; + } + + v = v.getView(n - 1); + if (sh != null) { + r = sh; + } + } + + passed = ((tableWidth - cellsWidth) > 10); + if (!passed) { + throw new RuntimeException("Test failed."); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + } +} diff --git a/test/jdk/javax/swing/text/html/TableView/bug4690812.java b/test/jdk/javax/swing/text/html/TableView/bug4690812.java new file mode 100644 index 00000000000..263bba71f14 --- /dev/null +++ b/test/jdk/javax/swing/text/html/TableView/bug4690812.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2003, 2023, 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 + * @bug 4690812 + * @summary Tests if tables are correctly formatted in some cases + * @key headful + * @run main bug4690812 +*/ + +import javax.swing.JEditorPane; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; +import javax.swing.text.View; +import javax.swing.text.html.HTMLEditorKit; + +import java.awt.Robot; +import java.awt.Shape; + +public class bug4690812 { + + private static boolean passed = false; + + private static JEditorPane jep; + private static JFrame f; + + public void init() { + + String text = + "" + + "" + + "" + + "" + + "
a
something
"; + + JFrame f = new JFrame(); + jep = new JEditorPane(); + jep.setEditorKit(new HTMLEditorKit()); + jep.setEditable(false); + + jep.setText(text); + + f.getContentPane().add(jep); + f.setSize(500,500); + f.setLocationRelativeTo(null); + f.setVisible(true); + } + + public static void main(String args[]) throws Exception { + Robot robot = new Robot(); + bug4690812 test = new bug4690812(); + try { + SwingUtilities.invokeAndWait(() -> test.init()); + robot.waitForIdle(); + robot.delay(1000); + Shape r = jep.getBounds(); + View v = jep.getUI().getRootView(jep); + int tableHeight = 0; + while (!(v instanceof javax.swing.text.html.ParagraphView)) { + int n = v.getViewCount(); + Shape sh = v.getChildAllocation(n - 1, r); + v = v.getView(n - 1); + if (sh != null) { + r = sh; + } + } + // left column in the second table row should have width == 1 + passed = (r.getBounds().width == 1) ? true : false; + if (!passed) { + throw new RuntimeException("Test failed."); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + } +} diff --git a/test/jdk/javax/swing/text/html/bug4210307.java b/test/jdk/javax/swing/text/html/bug4210307.java new file mode 100644 index 00000000000..6af4e62f805 --- /dev/null +++ b/test/jdk/javax/swing/text/html/bug4210307.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 1999, 2023, 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. + */ + +import javax.swing.JButton; +import javax.swing.JEditorPane; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.text.Document; +import javax.swing.text.Element; +import javax.swing.text.html.FormView; + +/* + * @test + * @bug 4210307 4210308 + * @summary Tests that FormView button text is internationalized + */ + +public class bug4210307 { + private static final String RESET_PROPERTY = "TEST RESET"; + private static final String SUBMIT_PROPERTY = "TEST SUBMIT"; + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(() -> { + Object oldReset = UIManager.put("FormView.resetButtonText", + RESET_PROPERTY); + Object oldSubmit = UIManager.put("FormView.submitButtonText", + SUBMIT_PROPERTY); + + try { + JEditorPane ep = new JEditorPane("text/html", + ""); + Document doc = ep.getDocument(); + Element elem = findInputElement(doc.getDefaultRootElement()); + TestView view = new TestView(elem); + view.test(SUBMIT_PROPERTY); + + ep = new JEditorPane("text/html", + ""); + doc = ep.getDocument(); + elem = findInputElement(doc.getDefaultRootElement()); + view = new TestView(elem); + view.test(RESET_PROPERTY); + } finally { + UIManager.put("FormView.resetButtonText", oldReset); + UIManager.put("FormView.submitButtonText", oldSubmit); + } + }); + } + + private static Element findInputElement(Element root) { + for (int i = 0; i < root.getElementCount(); i++) { + Element elem = root.getElement(i); + if (elem.getName().equals("input")) { + return elem; + } else { + Element e = findInputElement(elem); + if (e != null) return e; + } + } + return null; + } + + static class TestView extends FormView { + public TestView(Element elem) { + super(elem); + } + + public void test(String caption) { + JButton comp = (JButton) createComponent(); + if (!comp.getText().equals(caption)) { + throw new RuntimeException("Failed: '" + comp.getText() + + "' instead of `" + caption + "'"); + } + } + } +} diff --git a/test/jdk/javax/swing/text/html/bug4839739.java b/test/jdk/javax/swing/text/html/bug4839739.java new file mode 100644 index 00000000000..1dc5fbef123 --- /dev/null +++ b/test/jdk/javax/swing/text/html/bug4839739.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2003, 2023, 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. + */ + +import javax.swing.JEditorPane; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; +import javax.swing.text.html.HTMLEditorKit; +import java.awt.Component; +import java.awt.KeyboardFocusManager; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; + +/* + * @test + * @bug 4839739 + * @key headful + * @summary Tests if JEditorPane works correctly with HTML comments. + */ + +public class bug4839739 { + + private static JFrame jFrame; + private static JEditorPane jep; + private static volatile Point p; + + public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + robot.setAutoWaitForIdle(true); + robot.delay(50); + + SwingUtilities.invokeAndWait(bug4839739::createAndShowUI); + robot.waitForIdle(); + robot.delay(500); + + SwingUtilities.invokeAndWait(() -> p = jep.getLocationOnScreen()); + robot.delay(200); + + robot.mouseMove(p.x + 20, p.y + 20); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.keyPress(KeyEvent.VK_TAB); + robot.keyRelease(KeyEvent.VK_TAB); + robot.delay(300); + + Component comp = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner(); + if (!(comp instanceof JEditorPane)) { + throw new RuntimeException("Test failed." + + " JEditorPane doesn't work as expected with HTML comments"); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (jFrame != null) { + jFrame.dispose(); + } + }); + } + } + + private static void createAndShowUI() { + String text = "" + + "some always visible text"; + + jFrame = new JFrame("JEditorPane With HTML"); + jep = new JEditorPane(); + jep.setEditorKit(new HTMLEditorKit()); + jep.setEditable(false); + + jep.setText(text); + jFrame.getContentPane().add(jep); + jFrame.setSize(200,200); + jFrame.setLocationRelativeTo(null); + jFrame.setVisible(true); + } +} diff --git a/test/jdk/jdk/jfr/event/compiler/TestCompilerCompile.java b/test/jdk/jdk/jfr/event/compiler/TestCompilerCompile.java index 8b6b27261b9..f4b802b79ed 100644 --- a/test/jdk/jdk/jfr/event/compiler/TestCompilerCompile.java +++ b/test/jdk/jdk/jfr/event/compiler/TestCompilerCompile.java @@ -50,6 +50,7 @@ * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:CompileOnly=jdk.jfr.event.compiler.TestCompilerCompile::dummyMethod,jdk.jfr.event.compiler.TestCompilerCompile::doTest * jdk.jfr.event.compiler.TestCompilerCompile */ public class TestCompilerCompile { diff --git a/test/jdk/jdk/jfr/event/compiler/TestCompilerPhase.java b/test/jdk/jdk/jfr/event/compiler/TestCompilerPhase.java index e043736d1d7..7c1b762cf71 100644 --- a/test/jdk/jdk/jfr/event/compiler/TestCompilerPhase.java +++ b/test/jdk/jdk/jfr/event/compiler/TestCompilerPhase.java @@ -45,6 +45,7 @@ * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. + * -XX:-NeverActAsServerClassMachine * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:CompileOnly=jdk.jfr.event.compiler.TestCompilerPhase::dummyMethod * -XX:+SegmentedCodeCache -Xbootclasspath/a:. diff --git a/test/jdk/jdk/jfr/jcmd/TestJcmdDumpPathToGCRoots.java b/test/jdk/jdk/jfr/jcmd/TestJcmdDumpPathToGCRoots.java index ea1eba1c621..322e1146871 100644 --- a/test/jdk/jdk/jfr/jcmd/TestJcmdDumpPathToGCRoots.java +++ b/test/jdk/jdk/jfr/jcmd/TestJcmdDumpPathToGCRoots.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2023, 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 @@ -76,43 +76,50 @@ public static void main(String[] args) throws Exception { } private static void testDump(String pathToGcRoots, Map settings, boolean expectedChains) throws Exception { - try (Recording r = new Recording()) { - Map p = new HashMap<>(settings); - p.put(EventNames.OldObjectSample + "#" + Enabled.NAME, "true"); - r.setName("dodo"); - r.setSettings(p); - r.setToDisk(true); - r.start(); - clearLeak(); - System.out.println("Recording id: " + r.getId()); - System.out.println("Settings: " + settings.toString()); - System.out.println("Command: JFR.dump " + pathToGcRoots); - System.out.println("Chains expected: " + expectedChains); - buildLeak(); - System.gc(); - System.gc(); - File recording = new File("TestJcmdDumpPathToGCRoots" + r.getId() + ".jfr"); - recording.delete(); - JcmdHelper.jcmd("JFR.dump", "name=dodo", pathToGcRoots, "filename=" + recording.getAbsolutePath()); - r.setSettings(Collections.emptyMap()); - List events = RecordingFile.readAllEvents(recording.toPath()); - if (events.isEmpty()) { - throw new Exception("No events found in recoding"); - } - boolean chains = hasChains(events); - if (expectedChains && !chains) { - System.out.println(events); - throw new Exception("Expected chains but found none"); - } - if (!expectedChains && chains) { - System.out.println(events); - throw new Exception("Didn't expect chains but found some"); + while (true) { + try (Recording r = new Recording()) { + Map p = new HashMap<>(settings); + p.put(EventNames.OldObjectSample + "#" + Enabled.NAME, "true"); + r.setName("dodo"); + r.setSettings(p); + r.setToDisk(true); + r.start(); + clearLeak(); + System.out.println("Recording id: " + r.getId()); + System.out.println("Settings: " + settings.toString()); + System.out.println("Command: JFR.dump " + pathToGcRoots); + System.out.println("Chains expected: " + expectedChains); + buildLeak(); + System.gc(); + System.gc(); + File recording = new File("TestJcmdDumpPathToGCRoots" + r.getId() + ".jfr"); + recording.delete(); + JcmdHelper.jcmd("JFR.dump", "name=dodo", pathToGcRoots, "filename=" + recording.getAbsolutePath()); + r.setSettings(Collections.emptyMap()); + List events = RecordingFile.readAllEvents(recording.toPath()); + if (events.isEmpty()) { + System.out.println("No events found in recording. Retrying."); + continue; + } + boolean chains = hasChains(events); + if (expectedChains && !chains) { + System.out.println(events); + System.out.println("Expected chains but found none. Retrying."); + continue; + } + if (!expectedChains && chains) { + System.out.println(events); + System.out.println("Didn't expect chains but found some. Retrying."); + continue; + } + return; // Success } } } private static void clearLeak() { leak.clear(); + System.gc(); } private static boolean hasChains(List events) throws IOException { diff --git a/test/jdk/jdk/modules/etc/JmodExcludedFiles.java b/test/jdk/jdk/modules/etc/JmodExcludedFiles.java new file mode 100644 index 00000000000..6c25baf2b9f --- /dev/null +++ b/test/jdk/jdk/modules/etc/JmodExcludedFiles.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2024, 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 + * @bug 8159927 + * @modules java.base/jdk.internal.util + * @library /test/lib + * @run main JmodExcludedFiles + * @summary Test that JDK JMOD files do not include native debug symbols + */ + +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import jdk.test.lib.Platform; + +public class JmodExcludedFiles { + private static String javaHome = System.getProperty("java.home"); + + public static void main(String[] args) throws Exception { + Path jmods = Path.of(javaHome, "jmods"); + try (DirectoryStream stream = Files.newDirectoryStream(jmods, "*.jmod")) { + for (Path jmodFile : stream) { + try (ZipFile zip = new ZipFile(jmodFile.toFile())) { + JModSymbolFileMatcher jsfm = new JModSymbolFileMatcher(jmodFile.toString()); + if (zip.stream().map(ZipEntry::getName) + .anyMatch(jsfm::isNativeDebugSymbol)) { + throw new RuntimeException(jmodFile + " is expected not to include native debug symbols"); + } + } + } + } + } + + static class JModSymbolFileMatcher { + private String jmod; + + JModSymbolFileMatcher(String jmod) { + this.jmod = jmod; + } + + boolean isNativeDebugSymbol(String name) { + int index = name.indexOf("/"); + if (index < 0) { + throw new RuntimeException("unexpected entry name: " + name); + } + String section = name.substring(0, index); + if (section.equals("lib") || section.equals("bin")) { + if (Platform.isOSX()) { + String n = name.substring(index + 1); + int i = n.indexOf("/"); + if (i != -1) { + if (n.substring(0, i).endsWith(".dSYM")) { + System.err.println("Found symbols in " + jmod + ": " + name); + return true; + } + } + } + if (Platform.isWindows() && name.endsWith(".pdb")) { + // on Windows we check if we should have public symbols through --with-external-symbols-in-bundles=public (JDK-8237192) + String strippedpdb = javaHome + "/bin/" + name.substring(index + 1, name.length() - 4) + ".stripped.pdb"; + if (!Files.exists(Paths.get(strippedpdb))) { + System.err.println("Found symbols in " + jmod + ": " + name + + ". No stripped pdb file " + strippedpdb + " exists."); + return true; + } + } + if (name.endsWith(".diz") + || name.endsWith(".debuginfo") + || name.endsWith(".map")) { + System.err.println("Found symbols in " + jmod + ": " + name); + return true; + } + } + return false; + } + } +} diff --git a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java index 18f304e230d..32fba48cc3d 100644 --- a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java +++ b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java @@ -27,9 +27,9 @@ * @summary Interoperability tests with Actalis CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp * CAInterop actalisauthenticationrootca OCSP - * @run main/othervm/timeout=180 -Djava.security.debug=certpath,ocsp + * @run main/othervm/manual/timeout=180 -Djava.security.debug=certpath,ocsp * CAInterop actalisauthenticationrootca CRL */ @@ -39,8 +39,8 @@ * @summary Interoperability tests with Amazon's CA1 * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop amazonrootca1 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop amazonrootca1 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop amazonrootca1 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop amazonrootca1 CRL */ /* @@ -49,8 +49,7 @@ * @summary Interoperability tests with Amazon's CA2 * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop amazonrootca2 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop amazonrootca2 CRL + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop amazonrootca2 CRL */ /* @@ -59,8 +58,8 @@ * @summary Interoperability tests with Amazon's CA3 * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop amazonrootca3 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop amazonrootca3 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop amazonrootca3 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop amazonrootca3 CRL */ /* @@ -69,8 +68,8 @@ * @summary Interoperability tests with Amazon's CA4 * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop amazonrootca4 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop amazonrootca4 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop amazonrootca4 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop amazonrootca4 CRL */ /* @@ -79,8 +78,8 @@ * @summary Interoperability tests with Buypass Class 2 CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop buypassclass2ca OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop buypassclass2ca CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop buypassclass2ca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop buypassclass2ca CRL */ /* @@ -89,8 +88,8 @@ * @summary Interoperability tests with Buypass Class 3 CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop buypassclass3ca OCSP - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop buypassclass3ca CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop buypassclass3ca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop buypassclass3ca CRL */ /* @@ -99,8 +98,8 @@ * @summary Interoperability tests with Comodo RSA CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop comodorsaca OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop comodorsaca CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop comodorsaca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop comodorsaca CRL */ /* @@ -109,8 +108,8 @@ * @summary Interoperability tests with Comodo ECC CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop comodoeccca OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop comodoeccca CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop comodoeccca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop comodoeccca CRL */ /* @@ -119,8 +118,8 @@ * @summary Interoperability tests with Comodo userTrust RSA CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop usertrustrsaca OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop usertrustrsaca CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop usertrustrsaca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop usertrustrsaca CRL */ /* @@ -129,8 +128,8 @@ * @summary Interoperability tests with Comodo userTrust ECC CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop usertrusteccca OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop usertrusteccca CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop usertrusteccca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop usertrusteccca CRL */ /* @@ -139,7 +138,7 @@ * @summary Interoperability tests with Let's Encrypt ISRG Root X1 CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop letsencryptisrgx1 DEFAULT + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop letsencryptisrgx1 DEFAULT */ /* @@ -148,7 +147,7 @@ * @summary Interoperability tests with Let's Encrypt ISRG Root X2 CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop letsencryptisrgx2 DEFAULT + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop letsencryptisrgx2 DEFAULT */ /* @@ -157,8 +156,8 @@ * @summary Interoperability tests with GlobalSign R6 CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop globalsignrootcar6 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop globalsignrootcar6 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop globalsignrootcar6 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop globalsignrootcar6 CRL */ /* @@ -167,8 +166,8 @@ * @summary Interoperability tests with Entrust CAs * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop entrustrootcaec1 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop entrustrootcaec1 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop entrustrootcaec1 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop entrustrootcaec1 CRL */ /* @@ -177,8 +176,8 @@ * @summary Interoperability tests with Entrust CAs * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop entrustrootcag4 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop entrustrootcag4 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop entrustrootcag4 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop entrustrootcag4 CRL */ /* @@ -187,8 +186,8 @@ * @summary Interoperability tests with GoDaddy CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop godaddyrootg2ca OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop godaddyrootg2ca CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop godaddyrootg2ca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop godaddyrootg2ca CRL */ /* @@ -197,8 +196,8 @@ * @summary Interoperability tests with Starfield CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop starfieldrootg2ca OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop starfieldrootg2ca CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop starfieldrootg2ca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop starfieldrootg2ca CRL */ /* @@ -207,8 +206,7 @@ * @summary Interoperability tests with Google's GlobalSign R4 and GTS Root certificates * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop globalsigneccrootcar4 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop globalsigneccrootcar4 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop globalsigneccrootcar4 DEFAULT */ /* @@ -217,8 +215,7 @@ * @summary Interoperability tests with Google's GlobalSign R4 and GTS Root certificates * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop gtsrootcar1 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop gtsrootcar1 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop gtsrootcar1 DEFAULT */ /* @@ -227,8 +224,7 @@ * @summary Interoperability tests with Google's GlobalSign R4 and GTS Root certificates * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop gtsrootcar2 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop gtsrootcar2 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop gtsrootcar2 DEFAULT */ /* @@ -237,8 +233,7 @@ * @summary Interoperability tests with Google's GlobalSign R4 and GTS Root certificates * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop gtsrootecccar3 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop gtsrootecccar3 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop gtsrootecccar3 DEFAULT */ /* @@ -247,8 +242,7 @@ * @summary Interoperability tests with Google's GlobalSign R4 and GTS Root certificates * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop gtsrootecccar4 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop gtsrootecccar4 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop gtsrootecccar4 DEFAULT */ /* @@ -257,8 +251,8 @@ * @summary Interoperability tests with Microsoft TLS root CAs * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop microsoftecc2017 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop microsoftecc2017 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop microsoftecc2017 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop microsoftecc2017 CRL */ /* @@ -267,8 +261,8 @@ * @summary Interoperability tests with Microsoft TLS root CAs * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop microsoftrsa2017 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop microsoftrsa2017 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop microsoftrsa2017 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop microsoftrsa2017 CRL */ /* @@ -277,8 +271,8 @@ * @summary Interoperability tests with QuoVadis Root CA1 G3 CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop quovadisrootca1g3 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop quovadisrootca1g3 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop quovadisrootca1g3 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop quovadisrootca1g3 CRL */ /* @@ -287,8 +281,8 @@ * @summary Interoperability tests with QuoVadis Root CA2 G3 CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop quovadisrootca2g3 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop quovadisrootca2g3 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop quovadisrootca2g3 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop quovadisrootca2g3 CRL */ /* @@ -297,8 +291,8 @@ * @summary Interoperability tests with QuoVadis Root CA3 G3 CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop quovadisrootca3g3 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop quovadisrootca3g3 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop quovadisrootca3g3 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop quovadisrootca3g3 CRL */ /* @@ -307,8 +301,8 @@ * @summary Interoperability tests with DigiCert TLS ECC P384 Root G5 * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop digicerttlseccrootg5 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop digicerttlseccrootg5 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop digicerttlseccrootg5 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop digicerttlseccrootg5 CRL */ /* @@ -317,8 +311,8 @@ * @summary Interoperability tests with DigiCert TLS RSA4096 Root G5 * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop digicerttlsrsarootg5 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop digicerttlsrsarootg5 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop digicerttlsrsarootg5 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop digicerttlsrsarootg5 CRL */ /* @@ -327,8 +321,8 @@ * @summary Interoperability tests with SSL.com's RSA CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop sslrootrsaca OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop sslrootrsaca CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop sslrootrsaca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop sslrootrsaca CRL */ /* @@ -337,8 +331,8 @@ * @summary Interoperability tests with SSL.com's EV RSA CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop sslrootevrsaca OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop sslrootevrsaca CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop sslrootevrsaca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop sslrootevrsaca CRL */ /* @@ -347,8 +341,8 @@ * @summary Interoperability tests with SSL.com's ECC CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop sslrooteccca OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop sslrooteccca CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop sslrooteccca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop sslrooteccca CRL */ /* @@ -357,8 +351,8 @@ * @summary Interoperability tests with TeliaSonera Root CA v1 * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop teliasonerarootcav1 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop teliasonerarootcav1 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop teliasonerarootcav1 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop teliasonerarootcav1 CRL */ /* @@ -367,8 +361,8 @@ * @summary Interoperability tests with TWCA Global Root CA from TAIWAN-CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop twcaglobalrootca OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop twcaglobalrootca CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop twcaglobalrootca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop twcaglobalrootca CRL */ /* @@ -377,8 +371,8 @@ * @summary Interoperability tests with Certigna Root CAs from Dhimyotis * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop certignarootca OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop certignarootca CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop certignarootca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop certignarootca CRL */ /* @@ -387,8 +381,8 @@ * @summary Interoperability tests with AffirmTrust Commercial CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop affirmtrustcommercialca OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop affirmtrustcommercialca CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop affirmtrustcommercialca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop affirmtrustcommercialca CRL */ /* @@ -397,8 +391,8 @@ * @summary Interoperability tests with AffirmTrust Networking CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop affirmtrustnetworkingca OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop affirmtrustnetworkingca CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop affirmtrustnetworkingca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop affirmtrustnetworkingca CRL */ /* @@ -407,8 +401,8 @@ * @summary Interoperability tests with AffirmTrust Premium CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop affirmtrustpremiumca OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop affirmtrustpremiumca CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop affirmtrustpremiumca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop affirmtrustpremiumca CRL */ /* @@ -417,8 +411,8 @@ * @summary Interoperability tests with AffirmTrust Premium ECC CA * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop affirmtrustpremiumeccca OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop affirmtrustpremiumeccca CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop affirmtrustpremiumeccca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop affirmtrustpremiumeccca CRL */ /* @@ -427,8 +421,8 @@ * @summary Interoperability tests with Telia Root CA V2 * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop teliarootcav2 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop teliarootcav2 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop teliarootcav2 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop teliarootcav2 CRL */ /* @@ -437,8 +431,8 @@ * @summary Interoperability tests with eMudhra Root CA G1 * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop emsignrootcag1 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop emsignrootcag1 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop emsignrootcag1 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop emsignrootcag1 CRL */ /* @@ -447,8 +441,8 @@ * @summary Interoperability tests with eMudhra ECC Root CA G3 * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop emsigneccrootcag3 OCSP - * @run main/othervm -Djava.security.debug=certpath CAInterop emsigneccrootcag3 CRL + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop emsigneccrootcag3 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop emsigneccrootcag3 CRL */ /* @@ -457,7 +451,7 @@ * @summary Interoperability tests with Certainly Root R1 * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop certainlyrootr1 DEFAULT + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop certainlyrootr1 DEFAULT */ /* @@ -466,11 +460,33 @@ * @summary Interoperability tests with Certainly Root E1 * @library /test/lib * @build jtreg.SkippedException ValidatePathWithURL CAInterop - * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop certainlyroote1 DEFAULT + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop certainlyroote1 DEFAULT + */ + +/* + * @test id=globalsignr46 + * @bug 8316138 + * @summary Interoperability tests with GlobalSign Root R46 + * @library /test/lib + * @build jtreg.SkippedException ValidatePathWithURL CAInterop + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop globalsignr46 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop globalsignr46 CRL + */ + +/* + * @test id=globalsigne46 + * @bug 8316138 + * @summary Interoperability tests with GlobalSign Root E46 + * @library /test/lib + * @build jtreg.SkippedException ValidatePathWithURL CAInterop + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop globalsigne46 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop globalsigne46 CRL */ /** - * Collection of certificate validation tests for interoperability with external CAs + * Collection of certificate validation tests for interoperability with external CAs. + * These tests are marked as manual as they depend on external infrastructure and may fail + * with external reasons, for instance - change in CA test portal. */ public class CAInterop { @@ -638,6 +654,13 @@ private CATestURLs getTestURLs(String alias) { return new CATestURLs("https://valid.root-e1.certainly.com", "https://revoked.root-e1.certainly.com"); + case "globalsignr46": + return new CATestURLs("https://valid.r46.roots.globalsign.com", + "https://revoked.r46.roots.globalsign.com"); + case "globalsigne46": + return new CATestURLs("https://valid.e46.roots.globalsign.com", + "https://revoked.e46.roots.globalsign.com"); + default: throw new RuntimeException("No test setup found for: " + alias); } } diff --git a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CertignaCA.java b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CertignaCA.java index f1dd2d6229a..eb09d56a14e 100644 --- a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CertignaCA.java +++ b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CertignaCA.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, 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 @@ -26,8 +26,8 @@ * @bug 8245654 8256895 * @summary Interoperability tests with Certigna Root CAs from Dhimyotis * @build ValidatePathWithParams - * @run main/othervm -Djava.security.debug=certpath CertignaCA OCSP - * @run main/othervm -Djava.security.debug=certpath CertignaCA CRL + * @run main/othervm/manual -Djava.security.debug=certpath CertignaCA OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CertignaCA CRL */ public class CertignaCA { // Owner: CN=Certigna Services CA, OID.2.5.4.97=NTRFR-48146308100036, diff --git a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/DTrustCA.java b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/DTrustCA.java index 152e77907bb..13a2e8044da 100644 --- a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/DTrustCA.java +++ b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/DTrustCA.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -27,8 +27,8 @@ * @summary Interoperability tests with "D-Trust Root Class 3 CA 2 2009" and * "D-Trust Root Class 3 CA 2 EV 2009" CAs * @build ValidatePathWithParams - * @run main/othervm -Djava.security.debug=certpath DTrustCA OCSP - * @run main/othervm -Djava.security.debug=certpath DTrustCA CRL + * @run main/othervm/manual -Djava.security.debug=certpath DTrustCA OCSP + * @run main/othervm/manual -Djava.security.debug=certpath DTrustCA CRL */ public class DTrustCA { diff --git a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/DigicertCSRootG5.java b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/DigicertCSRootG5.java index 30ad81b1755..4b45bb857ba 100644 --- a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/DigicertCSRootG5.java +++ b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/DigicertCSRootG5.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, 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 @@ -26,8 +26,8 @@ * @bug 8318759 * @summary Interoperability tests with Digicert CS Root G5 certificates * @build ValidatePathWithParams - * @run main/othervm -Djava.security.debug=ocsp,certpath DigicertCSRootG5 OCSP - * @run main/othervm -Djava.security.debug=certpath DigicertCSRootG5 CRL + * @run main/othervm/manual -Djava.security.debug=ocsp,certpath DigicertCSRootG5 OCSP + * @run main/othervm/manual -Djava.security.debug=certpath DigicertCSRootG5 CRL */ public class DigicertCSRootG5 { diff --git a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/EmSignRootG2CA.java b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/EmSignRootG2CA.java index eb8fc2c2029..80f375c1ee6 100644 --- a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/EmSignRootG2CA.java +++ b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/EmSignRootG2CA.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, 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 @@ -26,8 +26,8 @@ * @bug 8319187 * @summary Interoperability tests with eMudhra emSign Root CA G2 CS root * @build ValidatePathWithParams - * @run main/othervm -Djava.security.debug=certpath EmSignRootG2CA OCSP - * @run main/othervm -Djava.security.debug=certpath EmSignRootG2CA CRL + * @run main/othervm/manual -Djava.security.debug=certpath EmSignRootG2CA OCSP + * @run main/othervm/manual -Djava.security.debug=certpath EmSignRootG2CA CRL */ public class EmSignRootG2CA { diff --git a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/HaricaCA.java b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/HaricaCA.java index 247502e6e6c..744e9b6bf34 100644 --- a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/HaricaCA.java +++ b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/HaricaCA.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, 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 @@ -26,8 +26,8 @@ * @bug 8256421 * @summary Interoperability tests with Harica CAs * @build ValidatePathWithParams - * @run main/othervm -Djava.security.debug=certpath HaricaCA OCSP - * @run main/othervm -Djava.security.debug=certpath HaricaCA CRL + * @run main/othervm/manual -Djava.security.debug=certpath HaricaCA OCSP + * @run main/othervm/manual -Djava.security.debug=certpath HaricaCA CRL */ /* diff --git a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/LuxTrustCA.java b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/LuxTrustCA.java index 63ba5e1bbab..258bf72f081 100644 --- a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/LuxTrustCA.java +++ b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/LuxTrustCA.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 @@ -26,8 +26,8 @@ * @bug 8232019 * @summary Interoperability tests with LuxTrust Global Root 2 CA * @build ValidatePathWithParams - * @run main/othervm -Djava.security.debug=certpath LuxTrustCA OCSP - * @run main/othervm -Djava.security.debug=certpath LuxTrustCA CRL + * @run main/othervm/manual -Djava.security.debug=certpath LuxTrustCA OCSP + * @run main/othervm/manual -Djava.security.debug=certpath LuxTrustCA CRL */ /* diff --git a/test/jdk/sun/awt/PaletteTester.java b/test/jdk/sun/awt/PaletteTester.java new file mode 100644 index 00000000000..7fb0d6b26ad --- /dev/null +++ b/test/jdk/sun/awt/PaletteTester.java @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2001, 2023, 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 + * @bug 4366799 + * @key headful + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @summary verifies that Windows applications react to palette + * changes in 8-bit mode correctly. + * @run main/manual PaletteTester +*/ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Frame; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.image.VolatileImage; +import javax.swing.ImageIcon; +import javax.swing.JPanel; +import java.io.File; + +public class PaletteTester { + + static VImageColors demo; + + private static final String INSTRUCTIONS = """ + This test should be run on any Windows platform in 8-bit + (256 color) display mode only. To check for errors, run a browser + application (Firefox or Internet Explorer) at the same time + and switch between this test and the browser (by clicking on the + title bars). + + The three panels in this test should look roughly the same (there + may be some dithering differences if you switch display modes + during the test, but the overall look should be the same. If + completely different colors are being used (either for the orange + background fill, the text, the image, or the rectangles), then the + test has failed. + """; + + private static void init() { + + int width = 300, height = 300; + + demo = new VImageColors(); + Frame f = new Frame("PaletteTester"); + f.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) {} + public void windowDeiconified(WindowEvent e) { demo.start(); } + public void windowIconified(WindowEvent e) { demo.stop(); } + }); + f.add(demo); + f.setSize(new Dimension(width, height)); + f.setLocationRelativeTo(null); + + PassFailJFrame.addTestWindow(f); + PassFailJFrame.positionTestWindow(f, PassFailJFrame.Position.HORIZONTAL); + f.setVisible(true); + + demo.start(); + + }//End init() + + public static void main( String args[] ) throws Exception { + + PassFailJFrame passFailJFrame = new PassFailJFrame.Builder() + .title("PaletteTester Instructions") + .instructions(INSTRUCTIONS) + .testTimeOut(5) + .rows(15) + .columns(40) + .screenCapture() + .build(); + + EventQueue.invokeAndWait(PaletteTester::init); + + + try { + passFailJFrame.awaitAndCheck(); + } finally { + demo.stop(); + } + }//main +} + +//************ Begin classes defined for the test **************** + +class VImageColors extends JPanel implements Runnable { + + VolatileImage vImage; + Image bImage; + private static int width = 300, height = 300; + private Thread thread; + Color fillColor = new Color(240, 188, 136); + Color textColor = new Color(40, 18, 97); + Color rectColor = new Color(0, 150, 0); + File f = new File(System.getProperty("test.src", "."), "duke.gif"); + Image duke = new ImageIcon(f.toString()).getImage(); + + public void initOffscreen() { + vImage = this.createVolatileImage(getWidth()/3, getHeight()); + bImage = this.createImage(getWidth()/3, getHeight()); + } + + public void paint(Graphics g) { + int width = getWidth(); + int height = getHeight(); + + if (vImage == null) { + initOffscreen(); + } + + // Render the left panel via VolatileImage + do { + if ( + vImage.validate(getGraphicsConfiguration()) == + VolatileImage.IMAGE_INCOMPATIBLE) + { + vImage = createVolatileImage(width/3, height); + } + Graphics vg = vImage.createGraphics(); + vg.setColor(fillColor); + vg.fillRect(0, 0, width/3, height); + vg.drawImage(duke, 0, 0, null); + vg.setColor(textColor); + vg.drawString("Vol Image", 5, height-1); + vg.setColor(rectColor); + vg.drawRect(0, 0, width/3-1, height-1); + vg.dispose(); + g.drawImage(vImage, 0, 0, width/3, height, null); + } while (vImage.contentsLost()); + + // Render the middle panel via BufferedImage + Graphics bg = bImage.getGraphics(); + bg.setColor(fillColor); + bg.fillRect(0, 0, width/3, height); + bg.drawImage(duke, 0, 0, null); + bg.setColor(textColor); + bg.drawString("Buff Image", 5, height-1); + bg.setColor(rectColor); + bg.drawRect(0, 0, width/3-1, height-1); + bg.dispose(); + g.drawImage(bImage, width/3, 0, width/3, height, null); + + // Render the right panel directly to the screen + g.setColor(fillColor); + g.fillRect(2*(width/3), 0, width/3, height); + g.drawImage(duke, 2*(width/3), 0, null); + g.setColor(textColor); + g.drawString("Screen", 2*(width/3) + 5, height-1); + g.setColor(rectColor); + g.drawRect(2*(width/3), 0, width/3-1, height-1); + + } + + public void start() { + thread = new Thread(this); + thread.setPriority(Thread.MIN_PRIORITY); + thread.start(); + } + + public synchronized void stop() { + thread = null; + } + + public void run() { + Thread me = Thread.currentThread(); + while (thread == me) { + try { + thread.sleep(100); + } catch (InterruptedException e) { break; } + } + thread = null; + } +} + +//************** End classes defined for the test ******************* diff --git a/test/jdk/sun/awt/duke.gif b/test/jdk/sun/awt/duke.gif new file mode 100644 index 00000000000..ed32e0ff79b Binary files /dev/null and b/test/jdk/sun/awt/duke.gif differ diff --git a/test/jdk/sun/awt/font/DoubleAntialiasTest.java b/test/jdk/sun/awt/font/DoubleAntialiasTest.java new file mode 100644 index 00000000000..e9057922895 --- /dev/null +++ b/test/jdk/sun/awt/font/DoubleAntialiasTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2000, 2023, 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. + */ + +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Panel; +import java.awt.Robot; + +import static java.awt.RenderingHints.KEY_ANTIALIASING; +import static java.awt.RenderingHints.KEY_TEXT_ANTIALIASING; +import static java.awt.RenderingHints.VALUE_ANTIALIAS_ON; +import static java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_ON; + +/* + * @test + * @bug 4357180 + * @key headful + * @summary When both KEY_ANTIALIASING and KEY_TEXT_ANTIALIASING hints + * were turned on, java aborts with EXCEPTION_ACCESS_VIOLATION + * at attempt to draw characters in Hebrew or Arabic. + * This could happen immediately or after several draws, + * depending on th locale and platform. This test draws + * large number of characters that are among this range repeatedly. + */ + +public class DoubleAntialiasTest extends Panel { + private static Frame frame; + + public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + EventQueue.invokeAndWait(() -> { + frame = new Frame(); + frame.setTitle("DoubleAntialiasTest"); + frame.add(new DoubleAntialiasTest()); + frame.pack(); + frame.setSize(500, 500); + frame.setVisible(true); + }); + + robot.waitForIdle(); + robot.delay(2000); + } catch (Exception e) { + throw new RuntimeException("Following exception occurred" + + " when testing Antialiasing Rendering hints: ", e); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + @Override + public void paint(Graphics g) { + Graphics2D g2 = (Graphics2D) g; + int y = 50; + for (int i = 0; i < 2; i++) { + int k = 5; + for (int j = 0x500; j < 0x700; j++) { + g2.setRenderingHint(KEY_TEXT_ANTIALIASING, + VALUE_TEXT_ANTIALIAS_ON); + g2.setRenderingHint(KEY_ANTIALIASING, + VALUE_ANTIALIAS_ON); + g2.drawString(String.valueOf((char) j), (5 + k), y); + k = k + 15; + } + k = 5; + y += 50; + for (int j = 0x700; j > 0x500; j--) { + g2.setRenderingHint(KEY_TEXT_ANTIALIASING, + VALUE_TEXT_ANTIALIAS_ON); + g2.setRenderingHint(KEY_ANTIALIASING, + VALUE_ANTIALIAS_ON); + g2.drawString(String.valueOf((char) j), (5 + k), y); + k = k + 15; + } + y += 50; + } + } +} diff --git a/test/jdk/sun/java2d/cmm/ColorConvertOp/ColConvCCMTest.java b/test/jdk/sun/java2d/cmm/ColorConvertOp/ColConvCCMTest.java index 22e055fbe8e..97ed058ff5a 100644 --- a/test/jdk/sun/java2d/cmm/ColorConvertOp/ColConvCCMTest.java +++ b/test/jdk/sun/java2d/cmm/ColorConvertOp/ColConvCCMTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2024, 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 @@ -23,7 +23,7 @@ /** * @test - * @bug 6476665 7033534 6830714 8052162 8196572 + * @bug 6476665 7033534 6830714 8052162 8196572 8326661 * @summary Verifies color conversion of Component Color Model based images * @run main ColConvCCMTest */ @@ -59,8 +59,8 @@ public class ColConvCCMTest extends ColConvTest { 2.5, // sRGB (isOpenProfile() ? 45.0 : 10.1), // LINEAR_RGB 10.5, // GRAY - (isOpenProfile() ? 215.0 : 45.5), // PYCC - (isOpenProfile() ? 56.0 : 47.5) // CIEXYZ + (isOpenProfile() ? 215.0 : 64.5), // PYCC + (isOpenProfile() ? 56.0 : 55.5) // CIEXYZ }; final static String [] gldImgNames = { diff --git a/test/jdk/sun/java2d/marlin/DefaultRenderingEngine.java b/test/jdk/sun/java2d/marlin/DefaultRenderingEngine.java new file mode 100644 index 00000000000..8ba6945d903 --- /dev/null +++ b/test/jdk/sun/java2d/marlin/DefaultRenderingEngine.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2020, 2024, 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. + */ + +import sun.java2d.pipe.RenderingEngine; + +/** + * @test + * @bug 8241307 + * @summary Verifies that the Marlin renderer is the default RenderingEngine + * @modules java.desktop/sun.java2d.pipe + */ +public final class DefaultRenderingEngine { + + public static void main(String[] argv) { + + final RenderingEngine engine = RenderingEngine.getInstance(); + + if (!engine.getClass().getSimpleName().contains("Marlin")) { + throw new RuntimeException("Marlin must be the default RenderingEngine"); + } + } +} diff --git a/test/jdk/sun/net/www/B8185898.java b/test/jdk/sun/net/www/B8185898.java index a50c6f93c7e..cfa54e15a52 100644 --- a/test/jdk/sun/net/www/B8185898.java +++ b/test/jdk/sun/net/www/B8185898.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, 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 @@ -23,7 +23,7 @@ /** * @test - * @bug 8185898 + * @bug 8185898 8163921 * @modules java.base/sun.net.www * @library /test/lib * @run main/othervm B8185898 @@ -143,32 +143,32 @@ static void testMessageHeaderMethods() throws IOException { // {{inputString1, expectedToString1, expectedPrint1}, {...}} String[][] strings = { {"HTTP/1.1 200 OK\r\n" - + "Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2\r\n" + + "Accept: */*\r\n" + "Connection: keep-alive\r\n" + "Host: 127.0.0.1:12345\r\n" + "User-agent: Java/12\r\n\r\nfoooo", "pairs: {null: HTTP/1.1 200 OK}" - + "{Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2}" + + "{Accept: */*}" + "{Connection: keep-alive}" + "{Host: 127.0.0.1:12345}" + "{User-agent: Java/12}", - "Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2\r\n" + "Accept: */*\r\n" + "Connection: keep-alive\r\n" + "Host: 127.0.0.1:12345\r\n" + "User-agent: Java/12\r\n\r\n"}, {"HTTP/1.1 200 OK\r\n" - + "Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2\r\n" + + "Accept: */*\r\n" + "Connection: keep-alive\r\n" + "Host: 127.0.0.1:12345\r\n" + "User-agent: Java/12\r\n" + "X-Header:\r\n\r\n", "pairs: {null: HTTP/1.1 200 OK}" - + "{Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2}" + + "{Accept: */*}" + "{Connection: keep-alive}" + "{Host: 127.0.0.1:12345}" + "{User-agent: Java/12}" + "{X-Header: }", - "Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2\r\n" + "Accept: */*\r\n" + "Connection: keep-alive\r\n" + "Host: 127.0.0.1:12345\r\n" + "User-agent: Java/12\r\n" diff --git a/test/jdk/sun/net/www/http/HttpClient/ProxyFromCache.java b/test/jdk/sun/net/www/http/HttpClient/ProxyFromCache.java index 920e5b0e254..f1d571498e7 100644 --- a/test/jdk/sun/net/www/http/HttpClient/ProxyFromCache.java +++ b/test/jdk/sun/net/www/http/HttpClient/ProxyFromCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2022, 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 @@ -25,13 +25,23 @@ * @test * @bug 6498566 * @summary URL.openConnection(Proxy.NO_PROXY) may connect through a proxy. - * @modules java.base/sun.net.www + * @library /test/lib * @run main/othervm ProxyFromCache */ -import java.net.*; -import java.io.*; -import sun.net.www.MessageHeader; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.URL; + +import jdk.test.lib.net.HttpHeaderParser; +import jdk.test.lib.net.URIBuilder; /* Creates a simple proxy and http server that just return 200 OK. * Open a URL pointing to the http server and specify that the @@ -124,15 +134,12 @@ public void run() { connectionCount++; InputStream is = sock.getInputStream(); OutputStream os = sock.getOutputStream(); - - MessageHeader headers = new MessageHeader (is); + HttpHeaderParser httpHeaderParser = new HttpHeaderParser(is); os.write(replyOK.getBytes("UTF-8")); - - headers = new MessageHeader (is); + httpHeaderParser = new HttpHeaderParser(is); // If we get here then we received a second request. connectionCount++; os.write(replyOK.getBytes("UTF-8")); - sock.close(); } catch (Exception e) { //e.printStackTrace(); diff --git a/test/jdk/sun/net/www/http/HttpClient/RequestURI.java b/test/jdk/sun/net/www/http/HttpClient/RequestURI.java index 667a0778abf..a5b55989b12 100644 --- a/test/jdk/sun/net/www/http/HttpClient/RequestURI.java +++ b/test/jdk/sun/net/www/http/HttpClient/RequestURI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2022, 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 @@ -25,13 +25,14 @@ * @test * @bug 6469663 * @summary HTTP Request-URI contains fragment when connecting through proxy - * @modules java.base/sun.net.www + * @library /test/lib * @run main/othervm RequestURI */ import java.net.*; import java.io.*; -import sun.net.www.MessageHeader; + +import jdk.test.lib.net.HttpHeaderParser; // Create a Server listening on port 5001 to act as the proxy. Requests // never need to be forwared from it. We are only interested in the @@ -91,8 +92,8 @@ public void run() { InputStream is = sock.getInputStream(); OutputStream os = sock.getOutputStream(); - MessageHeader headers = new MessageHeader (is); - String requestLine = headers.getValue(0); + HttpHeaderParser headers = new HttpHeaderParser (is); + String requestLine = headers.getRequestDetails(); int first = requestLine.indexOf(' '); int second = requestLine.lastIndexOf(' '); diff --git a/test/jdk/sun/net/www/protocol/http/CloseOptionHeader.java b/test/jdk/sun/net/www/protocol/http/CloseOptionHeader.java index bc1ec86fee4..28bb8af30cd 100644 --- a/test/jdk/sun/net/www/protocol/http/CloseOptionHeader.java +++ b/test/jdk/sun/net/www/protocol/http/CloseOptionHeader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2022, 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 @@ -24,16 +24,23 @@ /** * @test * @bug 6189206 - * @modules java.base/sun.net.www * @library /test/lib * @run main/othervm -Dhttp.keepAlive=false CloseOptionHeader * @summary HTTP client should set "Connection: close" header in request when keepalive is disabled */ -import java.net.*; -import java.util.*; -import java.io.*; -import sun.net.www.MessageHeader; +import java.io.BufferedOutputStream; +import java.io.InputStream; +import java.io.PrintStream; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.URL; +import java.util.List; + +import jdk.test.lib.net.HttpHeaderParser; import jdk.test.lib.net.URIBuilder; public class CloseOptionHeader implements Runnable { @@ -49,10 +56,15 @@ public void run() { /* check the request to find close connection option header */ InputStream is = s.getInputStream (); - MessageHeader mh = new MessageHeader(is); - String connHeader = mh.findValue("Connection"); - if (connHeader != null && connHeader.equalsIgnoreCase("close")) { - hasCloseHeader = true; + HttpHeaderParser mh = new HttpHeaderParser(is); + List connHeader = mh.getHeaderValue("Connection"); + if (connHeader != null) { + for(String value : connHeader) { + if (value.equalsIgnoreCase("close")) { + hasCloseHeader = true; + break; + } + } } PrintStream out = new PrintStream( diff --git a/test/jdk/sun/net/www/protocol/http/HttpHeaderParserTest.java b/test/jdk/sun/net/www/protocol/http/HttpHeaderParserTest.java new file mode 100644 index 00000000000..245cd49d518 --- /dev/null +++ b/test/jdk/sun/net/www/protocol/http/HttpHeaderParserTest.java @@ -0,0 +1,498 @@ + + +/* + * Copyright (c) 2022, 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 + * @bug 8061729 + * @library /test/lib + * @summary Sanity check that HttpHeaderParser works same as MessageHeader + * @modules java.base/sun.net.www java.base/sun.net.www.protocol.http:open + * @run testng/othervm HttpHeaderParserTest + */ + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +import static java.lang.String.format; +import static java.nio.charset.StandardCharsets.ISO_8859_1; +import static java.nio.charset.StandardCharsets.US_ASCII; +import jdk.test.lib.net.HttpHeaderParser; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import sun.net.www.MessageHeader; + +public class HttpHeaderParserTest { + @DataProvider(name = "responses") + public Object[][] responses() { + List responses = new ArrayList<>(); + + String[] basic = + { "HTTP/1.1 200 OK\r\n\r\n", + + "HTTP/1.1 200 OK\r\n" + + "Date: Mon, 15 Jan 2001 12:18:21 GMT\r\n" + + "Server: Apache/1.3.14 (Unix)\r\n" + + "Connection: close\r\n" + + "Content-Type: text/html; charset=iso-8859-1\r\n" + + "Content-Length: 10\r\n\r\n" + + "123456789", + + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 9\r\n" + + "Content-Type: text/html; charset=UTF-8\r\n\r\n" + + "XXXXX", + + "HTTP/1.1 200 OK\r\n" + + "X-Header: U\u00ffU\r\n" + // value with U+00FF - Extended Latin-1 + "Content-Length: 9\r\n" + + "Content-Type: text/html; charset=UTF-8\r\n\r\n" + + "XXXXX", + + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 9\r\n" + + "Content-Type: text/html; charset=UTF-8\r\n\r\n" + // more than one SP after ':' + "XXXXX", + + "HTTP/1.1 200 OK\r\n" + + "Content-Length:\t10\r\n" + + "Content-Type:\ttext/html; charset=UTF-8\r\n\r\n" + // HT separator + "XXXXX", + + "HTTP/1.1 200 OK\r\n" + + "Content-Length:\t\t10\r\n" + + "Content-Type:\t\ttext/html; charset=UTF-8\r\n\r\n" + // more than one HT after ':' + "XXXXX", + + "HTTP/1.1 407 Proxy Authorization Required\r\n" + + "Proxy-Authenticate: Basic realm=\"a fake realm\"\r\n\r\n", + + "HTTP/1.1 401 Unauthorized\r\n" + + "WWW-Authenticate: Digest realm=\"wally land\" domain=/ " + + "nonce=\"2B7F3A2B\" qop=\"auth\"\r\n\r\n", + + "HTTP/1.1 200 OK\r\n" + + "X-Foo:\r\n\r\n", // no value + + "HTTP/1.1 200 OK\r\n" + + "X-Foo:\r\n\r\n" + // no value, with response body + "Some Response Body", + + "HTTP/1.1 200 OK\r\n" + + "X-Foo:\r\n" + // no value, followed by another header + "Content-Length: 10\r\n\r\n" + + "Some Response Body", + + "HTTP/1.1 200 OK\r\n" + + "X-Foo:\r\n" + // no value, followed by another header, with response body + "Content-Length: 10\r\n\r\n", + + "HTTP/1.1 200 OK\r\n" + + "X-Foo: chegar\r\n" + + "X-Foo: dfuchs\r\n" + // same header appears multiple times + "Content-Length: 0\r\n" + + "X-Foo: michaelm\r\n" + + "X-Foo: prappo\r\n\r\n", + + "HTTP/1.1 200 OK\r\n" + + "X-Foo:\r\n" + // no value, same header appears multiple times + "X-Foo: dfuchs\r\n" + + "Content-Length: 0\r\n" + + "X-Foo: michaelm\r\n" + + "X-Foo: prappo\r\n\r\n", + + "HTTP/1.1 200 OK\r\n" + + "Accept-Ranges: bytes\r\n" + + "Cache-control: max-age=0, no-cache=\"set-cookie\"\r\n" + + "Content-Length: 132868\r\n" + + "Content-Type: text/html; charset=UTF-8\r\n" + + "Date: Sun, 05 Nov 2017 22:24:03 GMT\r\n" + + "Server: Apache/2.4.6 (Red Hat Enterprise Linux) OpenSSL/1.0.1e-fips Communique/4.2.2\r\n" + + "Set-Cookie: AWSELB=AF7927F5100F4202119876ED2436B5005EE;PATH=/;MAX-AGE=900\r\n" + + "Vary: Host,Accept-Encoding,User-Agent\r\n" + + "X-Mod-Pagespeed: 1.12.34.2-0\r\n" + + "Connection: keep-alive\r\n\r\n" + }; + Arrays.stream(basic).forEach(responses::add); + // add some tests where some of the CRLF are replaced + // by a single LF + Arrays.stream(basic) + .map(HttpHeaderParserTest::mixedCRLF) + .forEach(responses::add); + + String[] foldingTemplate = + { "HTTP/1.1 200 OK\r\n" + + "Content-Length: 9\r\n" + + "Content-Type: text/html;$NEWLINE" + // folding field-value with '\n'|'\r' + " charset=UTF-8\r\n" + // one preceding SP + "Connection: close\r\n\r\n" + + "XXYYZZAABBCCDDEE", + + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 19\r\n" + + "Content-Type: text/html;$NEWLINE" + // folding field-value with '\n'|'\r + " charset=UTF-8\r\n" + // more than one preceding SP + "Connection: keep-alive\r\n\r\n" + + "XXYYZZAABBCCDDEEFFGG", + + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 999\r\n" + + "Content-Type: text/html;$NEWLINE" + // folding field-value with '\n'|'\r + "\tcharset=UTF-8\r\n" + // one preceding HT + "Connection: close\r\n\r\n" + + "XXYYZZAABBCCDDEE", + + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 54\r\n" + + "Content-Type: text/html;$NEWLINE" + // folding field-value with '\n'|'\r + "\t\t\tcharset=UTF-8\r\n" + // more than one preceding HT + "Connection: keep-alive\r\n\r\n" + + "XXYYZZAABBCCDDEEFFGG", + + "HTTP/1.1 200 OK\r\n" + + "Content-Length: -1\r\n" + + "Content-Type: text/html;$NEWLINE" + // folding field-value with '\n'|'\r + "\t \t \tcharset=UTF-8\r\n" + // mix of preceding HT and SP + "Connection: keep-alive\r\n\r\n" + + "XXYYZZAABBCCDDEEFFGGHH", + + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 65\r\n" + + "Content-Type: text/html;$NEWLINE" + // folding field-value with '\n'|'\r + " \t \t charset=UTF-8\r\n" + // mix of preceding SP and HT + "Connection: keep-alive\r\n\r\n" + + "XXYYZZAABBCCDDEEFFGGHHII", + + "HTTP/1.1 401 Unauthorized\r\n" + + "WWW-Authenticate: Digest realm=\"wally land\"," + +"$NEWLINE domain=/," + +"$NEWLINE nonce=\"2B7F3A2B\"," + +"$NEWLINE\tqop=\"auth\"\r\n\r\n", + + }; + for (String newLineChar : new String[] { "\n", "\r", "\r\n" }) { + for (String template : foldingTemplate) + responses.add(template.replace("$NEWLINE", newLineChar)); + } + // add some tests where some of the CRLF are replaced + // by a single LF + for (String newLineChar : new String[] { "\n", "\r", "\r\n" }) { + for (String template : foldingTemplate) + responses.add(mixedCRLF(template).replace("$NEWLINE", newLineChar)); + } + + String[] bad = // much of this is to retain parity with legacy MessageHeaders + { "HTTP/1.1 200 OK\r\n" + + "Connection:\r\n\r\n", // empty value, no body + + "HTTP/1.1 200 OK\r\n" + + "Connection:\r\n\r\n" + // empty value, with body + "XXXXX", + + "HTTP/1.1 200 OK\r\n" + + ": no header\r\n\r\n", // no/empty header-name, no body, no following header + + "HTTP/1.1 200 OK\r\n" + + ": no; header\r\n" + // no/empty header-name, no body, following header + "Content-Length: 65\r\n\r\n", + + "HTTP/1.1 200 OK\r\n" + + ": no header\r\n" + // no/empty header-name + "Content-Length: 65\r\n\r\n" + + "XXXXX", + + "HTTP/1.1 200 OK\r\n" + + "X-foo: bar\r\n" + + " : no header\r\n" + // fold, not a blank header-name + "Content-Length: 65\r\n\r\n" + + "XXXXX", + + "HTTP/1.1 200 OK\r\n" + + "X-foo: bar\r\n" + + " \t : no header\r\n" + // fold, not a blank header-name + "Content-Length: 65\r\n\r\n" + + "XXXXX", + + "HTTP/1.1 200 OK\r\n" + + ": no header\r\n\r\n" + // no/empty header-name, followed by header + "XXXXX", + + "HTTP/1.1 200 OK\r\n" + + "Conte\r" + + "nt-Length: 9\r\n" + // fold/bad header name ??? without preceding space + "Content-Type: text/html; charset=UTF-8\r\n\r\n" + + "XXXXXYYZZ", + + "HTTP/1.0 404 Not Found\r\n" + + "header-without-colon\r\n\r\n", + + "HTTP/1.0 404 Not Found\r\n" + + "header-without-colon\r\n\r\n" + + "SOMEBODY", + + }; + Arrays.stream(bad).forEach(responses::add); + + return responses.stream().map(p -> new Object[] { p }).toArray(Object[][]::new); + } + + static final AtomicInteger index = new AtomicInteger(); + static final AtomicInteger limit = new AtomicInteger(1); + static final AtomicBoolean useCRLF = new AtomicBoolean(); + // A small method to replace part of the CRLF present in a string + // with simple LF. The method uses a deterministic algorithm based + // on current values of static index/limit/useCRLF counters. + // These counters are used to produce a stream of substitutes that + // looks like this: + // LF CRLF LF LF CRLF CRLF LF LF LF CRLF CRLF CRLF (then repeat from start) + static final String mixedCRLF(String headers) { + int next; + int start = 0; + int last = headers.lastIndexOf("\r\n"); + String prev = ""; + StringBuilder res = new StringBuilder(); + while ((next = headers.indexOf("\r\n", start)) > 0) { + res.append(headers.substring(start, next)); + if ("\n".equals(prev) && next == last) { + // for some reason the legacy MessageHeader parser will + // not consume the final LF if the headers are terminated + // by instead of . It consume + // but leaves the last in the stream. + // Here we just make sure to avoid using + // as that would cause the legacy parser to consume + // 1 byte less than the Http1HeadersParser - which + // does consume the last , as it should. + // if this is the last CRLF and the previous one + // was replaced by LF then use LF. + res.append(prev); + } else { + prev = useCRLF.get() ? "\r\n" : "\n"; + res.append(prev); + } + // skip CRLF + start = next + 2; + + // The idea is to substitute some of the CRLF with LF. + // Rather than doing this randomly, always use the following + // sequence: + // LF CRLF LF LF CRLF CRLF LF LF LF CRLF CRLF CRLF + index.incrementAndGet(); + if (index.get() == limit.get()) { + index.set(0); + if (useCRLF.get()) limit.incrementAndGet(); + if (limit.get() > 3) limit.set(1); + useCRLF.set(!useCRLF.get()); + } + } + res.append(headers.substring(start)); + return res.toString(); + } + + + @Test(dataProvider = "responses") + public void verifyHeaders(String respString) throws Exception { + System.out.println("\ntesting:\n\t" + respString + .replace("\r\n", "") + .replace("\r", "") + .replace("\n","") + .replace("LF>", "LF>\n\t")); + byte[] bytes = respString.getBytes(ISO_8859_1); + ByteArrayInputStream bais = new ByteArrayInputStream(bytes); + MessageHeader m = new MessageHeader(bais); + Map> messageHeaderMap = m.getHeaders(); + int availableBytes = bais.available(); + + HttpHeaderParser decoder = new HttpHeaderParser(); + ByteArrayInputStream headerStream = new ByteArrayInputStream(bytes); + int initialBytes = headerStream.available(); + decoder.parse(headerStream); + System.out.printf("HttpHeaderParser parsed %d bytes out of %d%n", initialBytes - headerStream.available(), bytes.length); + Map> decoderMap1 = decoder.getHeaderMap(); + + + // assert status-line + String statusLine1 = messageHeaderMap.get(null).get(0); + String statusLine2 = decoder.getRequestDetails(); + if (statusLine1.startsWith("HTTP")) {// skip the case where MH's messes up the status-line + assertEquals(statusLine2, statusLine1, "Status-line not equal"); + } else { + assertTrue(statusLine2.startsWith("HTTP/1."), "Status-line not HTTP/1."); + } + + // remove the null'th entry with is the status-line + Map> map = new HashMap<>(); + for (Map.Entry> e : messageHeaderMap.entrySet()) { + if (e.getKey() != null) { + map.put(e.getKey(), e.getValue()); + } + } + messageHeaderMap = map; + + assertHeadersEqual(messageHeaderMap, decoderMap1, + "messageHeaderMap not equal to decoderMap1"); + + assertEquals(availableBytes, headerStream.available(), + String.format("stream available (%d) not equal to remaining (%d)", + availableBytes, headerStream.available())); + } + + @DataProvider(name = "errors") + public Object[][] errors() { + List responses = new ArrayList<>(); + + // These responses are parsed, somewhat, by MessageHeaders but give + // nonsensible results. They, correctly, fail with the Http1HeaderParser. + String[] bad = + {// "HTTP/1.1 402 Payment Required\r\n" + + // "Content-Length: 65\r\n\r", // missing trailing LF //TODO: incomplete + + "HTTP/1.1 402 Payment Required\r\n" + + "Content-Length: 65\r\n\rT\r\n\r\nGGGGGG", + + "HTTP/1.1 200OK\r\n\rT", + + "HTTP/1.1 200OK\rT", + + "HTTP/1.0 FOO\r\n", + + "HTTP/1.1 BAR\r\n", + + "HTTP/1.1 +99\r\n", + + "HTTP/1.1 -22\r\n", + + "HTTP/1.1 -20 \r\n", + + "HTTP/1.1 200 OK\r\n" + + "X-fo\u00ffo: foo\r\n" + // invalid char in name + "Content-Length: 5\r\n" + + "Content-Type: text/html; charset=UTF-8\r\n\r\n" + + "XXXXX", + + "HTTP/1.1 200 OK\r\n" + + "HTTP/1.1 200 OK\r\n" + + "X-foo : bar\r\n" + // trim space after name + "Content-Length: 5\r\n" + + "Content-Type: text/html; charset=UTF-8\r\n\r\n" + + "XXXXX", + + "HTTP/1.1 200 OK\r\n" + + " X-foo: bar\r\n" + // trim space before name + "Content-Length: 5\r\n" + + "Content-Type: text/html; charset=UTF-8\r\n\r\n" + + "XXXXX", + + "HTTP/1.1 200 OK\r\n" + + "X foo: bar\r\n" + // invalid space in name + "Content-Length: 5\r\n" + + "Content-Type: text/html; charset=UTF-8\r\n\r\n" + + "XXXXX", + + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 5\r\n" + + "Content Type: text/html; charset=UTF-8\r\n\r\n" + // invalid space in name + "XXXXX", + + "HTTP/1.1 200 OK\r\n" + + "Conte\r" + + " nt-Length: 9\r\n" + // fold results in space in header name + "Content-Type: text/html; charset=UTF-8\r\n\r\n" + + "XXXXX", + + "HTTP/1.1 200 OK\r\n" + + " : no header\r\n" + // all blank header-name (not fold) + "Content-Length: 65\r\n\r\n" + + "XXXXX", + + "HTTP/1.1 200 OK\r\n" + + " \t : no header\r\n" + // all blank header-name (not fold) + "Content-Length: 65\r\n\r\n" + + "XXXXX", + + }; + Arrays.stream(bad).forEach(responses::add); + + return responses.stream().map(p -> new Object[] { p }).toArray(Object[][]::new); + } + + @Test(dataProvider = "errors", expectedExceptions = IOException.class) + public void errors(String respString) throws IOException { + byte[] bytes = respString.getBytes(US_ASCII); + HttpHeaderParser decoder = new HttpHeaderParser(); + ByteArrayInputStream bais = new ByteArrayInputStream(bytes); + decoder.parse(bais); + } + + void assertHeadersEqual(Map> expected, + Map> actual, + String msg) { + + if (expected.equals(actual)) + return; + + assertEquals(expected.size(), actual.size(), + format("%s. Expected size %d, actual size %s. %nexpected= %s,%n actual=%s.", + msg, expected.size(), actual.size(), mapToString(expected), mapToString(actual))); + + for (Map.Entry> e : expected.entrySet()) { + String key = e.getKey(); + List values = e.getValue(); + + boolean found = false; + for (Map.Entry> other: actual.entrySet()) { + if (key.equalsIgnoreCase(other.getKey())) { + found = true; + List otherValues = other.getValue(); + assertEquals(values.size(), otherValues.size(), + format("%s. Expected list size %d, actual size %s", + msg, values.size(), otherValues.size())); + if (!(values.containsAll(otherValues) && otherValues.containsAll(values))) + assertTrue(false, format("Lists are unequal [%s] [%s]", values, otherValues)); + break; + } + } + assertTrue(found, format("header name, %s, not found in %s", key, actual)); + } + } + + static String mapToString(Map> map) { + StringBuilder sb = new StringBuilder(); + List sortedKeys = new ArrayList(map.keySet()); + Collections.sort(sortedKeys); + for (String key : sortedKeys) { + List values = map.get(key); + sb.append("\n\t" + key + " | " + values); + } + return sb.toString(); + } +} diff --git a/test/jdk/sun/net/www/protocol/http/NTLMTest.java b/test/jdk/sun/net/www/protocol/http/NTLMTest.java index 73d0cb98603..37282f15b03 100644 --- a/test/jdk/sun/net/www/protocol/http/NTLMTest.java +++ b/test/jdk/sun/net/www/protocol/http/NTLMTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2022, 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 @@ -24,7 +24,6 @@ /* * @test * @bug 6520665 6357133 - * @modules java.base/sun.net.www * @library /test/lib * @run main/othervm NTLMTest * @summary 6520665 & 6357133: NTLM authentication issues. @@ -32,7 +31,8 @@ import java.net.*; import java.io.*; -import sun.net.www.MessageHeader; + +import jdk.test.lib.net.HttpHeaderParser; import jdk.test.lib.net.URIBuilder; public class NTLMTest @@ -160,7 +160,7 @@ static void handleConnection(Socket s, String[] resp, int start, int end) { OutputStream os = s.getOutputStream(); for (int i=start; i server // client <--- 401 ---- server try (Socket s = ss.accept()) { - new MessageHeader().parseHeader(s.getInputStream()); + new HttpHeaderParser().parse(s.getInputStream()); s.getOutputStream().write(reply.getBytes("US-ASCII")); } @@ -171,10 +171,10 @@ static void test(String... schemes) throws IOException { // client <--- 200 ---- server String auth; try (Socket s = ss.accept()) { - MessageHeader mh = new MessageHeader(); - mh.parseHeader(s.getInputStream()); + HttpHeaderParser mh = new HttpHeaderParser(); + mh.parse(s.getInputStream()); s.getOutputStream().write(OKAY.getBytes("US-ASCII")); - auth = mh.findValue("Authorization"); + auth = mh.getHeaderValue("Authorization").get(0); } // check Authorization header @@ -208,7 +208,7 @@ static void testNTLM() throws Exception { // client ---- GET ---> server // client <--- 401 ---- client try (Socket s = ss.accept()) { - new MessageHeader().parseHeader(s.getInputStream()); + new HttpHeaderParser().parse(s.getInputStream()); s.getOutputStream().write(reply.getBytes("US-ASCII")); } diff --git a/test/jdk/sun/net/www/protocol/http/RetryUponTimeout.java b/test/jdk/sun/net/www/protocol/http/RetryUponTimeout.java index bfda1663259..b2214780c2e 100644 --- a/test/jdk/sun/net/www/protocol/http/RetryUponTimeout.java +++ b/test/jdk/sun/net/www/protocol/http/RetryUponTimeout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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 @@ -26,13 +26,13 @@ * @bug 4772077 * @library /test/lib * @summary using defaultReadTimeout appear to retry request upon timeout - * @modules java.base/sun.net.www */ import java.net.*; import java.io.*; + +import jdk.test.lib.net.HttpHeaderParser; import jdk.test.lib.net.URIBuilder; -import sun.net.www.*; public class RetryUponTimeout implements Runnable { // run server @@ -42,7 +42,7 @@ public void run(){ for (int i = 0; i < 2; i++) { socket = server.accept(); InputStream is = socket.getInputStream (); - MessageHeader header = new MessageHeader (is); + HttpHeaderParser header = new HttpHeaderParser (is); count++; } } catch (Exception ex) { diff --git a/test/jdk/sun/net/www/protocol/http/UserAgent.java b/test/jdk/sun/net/www/protocol/http/UserAgent.java index 7db84882488..40ff5d3106f 100644 --- a/test/jdk/sun/net/www/protocol/http/UserAgent.java +++ b/test/jdk/sun/net/www/protocol/http/UserAgent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2022, 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 @@ -25,7 +25,6 @@ * @test * @bug 4512200 * @library /test/lib - * @modules java.base/sun.net.www * @run main/othervm -Dhttp.agent=foo UserAgent * @run main/othervm -Dhttp.agent=foo -Djava.net.preferIPv6Addresses=true UserAgent * @summary HTTP header "User-Agent" format incorrect @@ -34,8 +33,9 @@ import java.io.*; import java.util.*; import java.net.*; + +import jdk.test.lib.net.HttpHeaderParser; import jdk.test.lib.net.URIBuilder; -import sun.net.www.MessageHeader; class Server extends Thread { Server (ServerSocket server) { @@ -46,8 +46,8 @@ public void run () { String version = System.getProperty ("java.version"); String expected = "foo Java/"+version; Socket s = server.accept (); - MessageHeader header = new MessageHeader (s.getInputStream()); - String v = header.findValue ("User-Agent"); + HttpHeaderParser header = new HttpHeaderParser (s.getInputStream()); + String v = header.getHeaderValue ("User-Agent").get(0); if (!expected.equals (v)) { error ("Got unexpected User-Agent: " + v); } else { diff --git a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/B6226610.java b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/B6226610.java index ec75bcc3e11..9fca12c9958 100644 --- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/B6226610.java +++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/B6226610.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2022, 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 @@ -25,7 +25,7 @@ * @test * @bug 6226610 6973030 * @summary HTTP tunnel connections send user headers to proxy - * @modules java.base/sun.net.www + * @library /test/lib * @run main/othervm B6226610 */ @@ -37,7 +37,9 @@ import java.io.*; import java.net.*; -import sun.net.www.MessageHeader; + +import jdk.test.lib.net.HttpHeaderParser; + public class B6226610 { static HeaderCheckerProxyTunnelServer proxy; @@ -138,21 +140,21 @@ public int getLocalPort() { private void processRequests() throws IOException { InputStream in = clientSocket.getInputStream(); - MessageHeader mheader = new MessageHeader(in); - String statusLine = mheader.getValue(0); + HttpHeaderParser mheader = new HttpHeaderParser(in); + String statusLine = mheader.getRequestDetails(); if (statusLine.startsWith("CONNECT")) { // retrieve the host and port info from the status-line retrieveConnectInfo(statusLine); - if (mheader.findValue("X-TestHeader") != null) { + if (mheader.getHeaderValue("X-TestHeader") != null) { System.out.println("Proxy should not receive user defined headers for tunneled requests"); failed = true; } // 6973030 String value; - if ((value = mheader.findValue("Proxy-Connection")) == null || + if ((value = mheader.getHeaderValue("Proxy-Connection").get(0)) == null || !value.equals("keep-alive")) { System.out.println("Proxy-Connection:keep-alive not being sent"); failed = true; diff --git a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/TunnelProxy.java b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/TunnelProxy.java index 5b6deec2512..2326c57d9cf 100644 --- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/TunnelProxy.java +++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/TunnelProxy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2022, 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 @@ -45,7 +45,8 @@ import java.util.Iterator; import java.util.Set; -import sun.net.www.MessageHeader; +import jdk.test.lib.net.HttpHeaderParser; + public class TunnelProxy { @@ -262,9 +263,9 @@ private boolean read (SocketChannel chan, SelectionKey key) { boolean res; try { InputStream is = new BufferedInputStream (new NioInputStream (chan)); - String requestline = readLine (is); - MessageHeader mhead = new MessageHeader (is); - String[] req = requestline.split (" "); + HttpHeaderParser mHead = new HttpHeaderParser (is); + String requestLine = mHead.getRequestDetails(); + String[] req = requestLine.split (" "); if (req.length < 2) { /* invalid request line */ return false; diff --git a/test/jdk/sun/security/krb5/auto/MSOID2.java b/test/jdk/sun/security/krb5/auto/MSOID2.java index 3a3b3cf6c26..0b7545ffbe2 100644 --- a/test/jdk/sun/security/krb5/auto/MSOID2.java +++ b/test/jdk/sun/security/krb5/auto/MSOID2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2020, 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 @@ -32,7 +32,7 @@ */ import sun.security.jgss.GSSUtil; -import sun.security.util.HexDumpEncoder; +import jdk.test.lib.hexdump.HexPrinter; // The basic krb5 test skeleton you can copy from public class MSOID2 { @@ -72,7 +72,7 @@ public static void main(String[] args) throws Exception { nt[pos] = (byte)newLen; } t = nt; - new HexDumpEncoder().encodeBuffer(t, System.out); + HexPrinter.simple().format(t); } if (t != null || !s.x().isEstablished()) t = s.take(t); if (c.x().isEstablished() && s.x().isEstablished()) break; diff --git a/test/jdk/sun/security/krb5/etype/KerberosAesSha2.java b/test/jdk/sun/security/krb5/etype/KerberosAesSha2.java index 79c8053bf0a..c738e063e02 100644 --- a/test/jdk/sun/security/krb5/etype/KerberosAesSha2.java +++ b/test/jdk/sun/security/krb5/etype/KerberosAesSha2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2020, 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 @@ -23,6 +23,7 @@ /* * @test * @bug 8014628 + * @library /test/lib * @modules java.base/sun.security.util * java.security.jgss/sun.security.krb5.internal.crypto.dk:+open * @summary https://tools.ietf.org/html/rfc8009 Test Vectors @@ -33,7 +34,7 @@ import java.util.Arrays; import sun.security.krb5.internal.crypto.dk.AesSha2DkCrypto; -import sun.security.util.HexDumpEncoder; +import jdk.test.lib.hexdump.HexPrinter; public class KerberosAesSha2 { @@ -204,6 +205,6 @@ private static void check(byte[] b1, byte[] b2) throws Exception { } private static void dump(byte[] data) throws Exception { - new HexDumpEncoder().encodeBuffer(data, System.err); + HexPrinter.simple().dest(System.err).format(data); } } diff --git a/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java b/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java index 72b9922e89b..3c4a50c03ed 100644 --- a/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java +++ b/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java @@ -29,7 +29,7 @@ * 8223499 8225392 8232019 8234245 8233223 8225068 8225069 8243321 8243320 * 8243559 8225072 8258630 8259312 8256421 8225081 8225082 8225083 8245654 * 8305975 8304760 8307134 8295894 8314960 8317373 8317374 8318759 8319187 - * 8321408 + * 8321408 8316138 * @summary Check root CA entries in cacerts file */ import java.io.ByteArrayInputStream; @@ -48,12 +48,12 @@ public class VerifyCACerts { + File.separator + "security" + File.separator + "cacerts"; // The numbers of certs now. - private static final int COUNT = 108; + private static final int COUNT = 110; // SHA-256 of cacerts, can be generated with // shasum -a 256 cacerts | sed -e 's/../&:/g' | tr '[:lower:]' '[:upper:]' | cut -c1-95 private static final String CHECKSUM - = "81:D4:84:F6:92:78:A4:82:25:06:DC:42:25:C9:5D:6C:63:E4:99:CE:BC:ED:66:B3:8C:BA:E6:BA:6B:34:0F:01"; + = "C1:68:B4:AC:51:BF:B5:C6:FD:20:69:17:E1:AF:E4:5B:01:9B:AA:3F:C3:9A:80:A8:51:53:74:2C:A2:04:B0:FF"; // map of cert alias to SHA-256 fingerprint @SuppressWarnings("serial") @@ -275,6 +275,10 @@ public class VerifyCACerts { "77:B8:2C:D8:64:4C:43:05:F7:AC:C5:CB:15:6B:45:67:50:04:03:3D:51:C6:0C:62:02:A8:E0:C3:34:67:D3:A0"); put("certainlyroote1 [jdk]", "B4:58:5F:22:E4:AC:75:6A:4E:86:12:A1:36:1C:5D:9D:03:1A:93:FD:84:FE:BB:77:8F:A3:06:8B:0F:C4:2D:C2"); + put("globalsignr46 [jdk]", + "4F:A3:12:6D:8D:3A:11:D1:C4:85:5A:4F:80:7C:BA:D6:CF:91:9D:3A:5A:88:B0:3B:EA:2C:63:72:D9:3C:40:C9"); + put("globalsigne46 [jdk]", + "CB:B9:C4:4D:84:B8:04:3E:10:50:EA:31:A6:9F:51:49:55:D7:BF:D2:E2:C6:B4:93:01:01:9A:D6:1D:9F:50:58"); } }; diff --git a/test/jdk/sun/security/mscapi/KeytoolChangeAlias.java b/test/jdk/sun/security/mscapi/KeytoolChangeAlias.java index 4cf36977264..087e93dabec 100644 --- a/test/jdk/sun/security/mscapi/KeytoolChangeAlias.java +++ b/test/jdk/sun/security/mscapi/KeytoolChangeAlias.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -25,6 +25,7 @@ import jdk.test.lib.security.CertUtils; import java.security.KeyStore; +import java.security.SecureRandom; /* * @test @@ -35,15 +36,17 @@ */ public class KeytoolChangeAlias { public static void main(String[] args) throws Exception { - + SecureRandom random = new SecureRandom(); + String alias = Integer.toString(random.nextInt(8192 - 1000) + 1000); + String newAlias = alias + "1"; KeyStore ks = KeyStore.getInstance("Windows-MY"); ks.load(null, null); try { - ks.setCertificateEntry("246810", CertUtils.getCertFromFile("246810.cer")); + ks.setCertificateEntry(alias, CertUtils.getCertFromFile("246810.cer")); - if (ks.containsAlias("13579")) { - ks.deleteEntry("13579"); + if (ks.containsAlias(newAlias)) { + ks.deleteEntry(newAlias); } int before = ks.size(); @@ -52,8 +55,8 @@ public static void main(String[] args) throws Exception { SecurityTools.keytool("-changealias", "-storetype", "Windows-My", - "-alias", "246810", - "-destalias", "13579").shouldHaveExitValue(0); + "-alias", alias, + "-destalias", newAlias).shouldHaveExitValue(0); ks.load(null, null); @@ -63,13 +66,23 @@ public static void main(String[] args) throws Exception { + ". After: " + ks.size()); } - if (!ks.containsAlias("13579")) { + if (!ks.containsAlias(newAlias)) { throw new Exception("error: cannot find the new alias name" + " in the Windows-MY store"); } } finally { - ks.deleteEntry("13579"); - ks.deleteEntry("246810"); + try { + ks.deleteEntry(newAlias); + } catch (Exception e) { + System.err.println("Couldn't delete alias " + newAlias); + e.printStackTrace(System.err); + } + try { + ks.deleteEntry(alias); + } catch (Exception e) { + System.err.println("Couldn't delete alias " + alias); + e.printStackTrace(System.err); + } ks.store(null, null); } } diff --git a/test/jdk/sun/security/mscapi/PublicKeyInterop.java b/test/jdk/sun/security/mscapi/PublicKeyInterop.java index 85da7e041b1..f3b646bc372 100644 --- a/test/jdk/sun/security/mscapi/PublicKeyInterop.java +++ b/test/jdk/sun/security/mscapi/PublicKeyInterop.java @@ -35,7 +35,7 @@ import javax.crypto.*; import jdk.test.lib.SecurityTools; -import sun.security.util.HexDumpEncoder; +import jdk.test.lib.hexdump.HexPrinter; /* * Confirm interoperability of RSA public keys between SunMSCAPI and SunJCE @@ -84,29 +84,29 @@ static void run() throws Exception { System.out.println(); byte[] plain = new byte[] {0x01, 0x02, 0x03, 0x04, 0x05}; - HexDumpEncoder hde = new HexDumpEncoder(); - System.out.println("Plaintext:\n" + hde.encode(plain) + "\n"); + HexPrinter hp = HexPrinter.simple(); + System.out.println("Plaintext:\n" + hp.toString(plain) + "\n"); Cipher rsa = Cipher.getInstance("RSA/ECB/PKCS1Padding"); rsa.init(Cipher.ENCRYPT_MODE, myPuKey); byte[] encrypted = rsa.doFinal(plain); System.out.println("Encrypted plaintext using RSA Cipher from " + rsa.getProvider().getName() + " JCE provider\n"); - System.out.println(hde.encode(encrypted) + "\n"); + System.out.println(hp.toString(encrypted) + "\n"); Cipher rsa2 = Cipher.getInstance("RSA/ECB/PKCS1Padding", "SunMSCAPI"); rsa2.init(Cipher.ENCRYPT_MODE, myPuKey); byte[] encrypted2 = rsa2.doFinal(plain); System.out.println("Encrypted plaintext using RSA Cipher from " + rsa2.getProvider().getName() + " JCE provider\n"); - System.out.println(hde.encode(encrypted2) + "\n"); + System.out.println(hp.toString(encrypted2) + "\n"); Cipher rsa3 = Cipher.getInstance("RSA/ECB/PKCS1Padding", "SunMSCAPI"); rsa3.init(Cipher.DECRYPT_MODE, myPrKey); byte[] decrypted = rsa3.doFinal(encrypted); System.out.println("Decrypted first ciphertext using RSA Cipher from " + rsa3.getProvider().getName() + " JCE provider\n"); - System.out.println(hde.encode(decrypted) + "\n"); + System.out.println(hp.toString(decrypted) + "\n"); if (! Arrays.equals(plain, decrypted)) { throw new Exception("First decrypted ciphertext does not match " + "original plaintext"); @@ -115,7 +115,7 @@ static void run() throws Exception { decrypted = rsa3.doFinal(encrypted2); System.out.println("Decrypted second ciphertext using RSA Cipher from " + rsa3.getProvider().getName() + " JCE provider\n"); - System.out.println(hde.encode(decrypted) + "\n"); + System.out.println(hp.toString(decrypted) + "\n"); if (! Arrays.equals(plain, decrypted)) { throw new Exception("Second decrypted ciphertext does not match " + "original plaintext"); diff --git a/test/jdk/sun/security/pkcs/pkcs7/SignerOrder.java b/test/jdk/sun/security/pkcs/pkcs7/SignerOrder.java index ef247d5906a..875ca5935e4 100644 --- a/test/jdk/sun/security/pkcs/pkcs7/SignerOrder.java +++ b/test/jdk/sun/security/pkcs/pkcs7/SignerOrder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2020, 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 @@ -25,6 +25,7 @@ * @test * @bug 8048357 * @summary test PKCS7 data signing, encoding and verification + * @library /test/lib * @modules java.base/sun.security.pkcs * java.base/sun.security.util * java.base/sun.security.x509 @@ -40,7 +41,6 @@ import java.security.SignatureException; import java.security.cert.X509Certificate; import java.util.Date; -import sun.security.util.HexDumpEncoder; import sun.security.pkcs.ContentInfo; import sun.security.pkcs.PKCS7; import sun.security.pkcs.SignerInfo; @@ -55,11 +55,10 @@ import sun.security.x509.X509CertImpl; import sun.security.x509.X509CertInfo; import sun.security.x509.X509Key; +import jdk.test.lib.hexdump.HexPrinter; public class SignerOrder { - static final HexDumpEncoder hexDump = new HexDumpEncoder(); - //signer infos static final byte[] data1 = "12345".getBytes(); static final byte[] data2 = "abcde".getBytes(); @@ -120,7 +119,7 @@ static void printSignerInfos(SignerInfo signerInfo) throws IOException { signerInfo.derEncode(strm); System.out.println("SignerInfo, length: " + strm.toByteArray().length); - System.out.println(hexDump.encode(strm.toByteArray())); + HexPrinter.simple().format(strm.toByteArray()); System.out.println("\n"); strm.reset(); } @@ -131,7 +130,7 @@ static void printSignerInfos(SignerInfo[] signerInfos) throws IOException { signerInfos[i].derEncode(strm); System.out.println("SignerInfo[" + i + "], length: " + strm.toByteArray().length); - System.out.println(hexDump.encode(strm.toByteArray())); + HexPrinter.simple().format(strm.toByteArray()); System.out.println("\n"); strm.reset(); } diff --git a/test/jdk/sun/security/pkcs/pkcs8/PKCS8Test.java b/test/jdk/sun/security/pkcs/pkcs8/PKCS8Test.java index 1bd9f0e54e1..f0555ce59db 100644 --- a/test/jdk/sun/security/pkcs/pkcs8/PKCS8Test.java +++ b/test/jdk/sun/security/pkcs/pkcs8/PKCS8Test.java @@ -25,6 +25,7 @@ * @test * @bug 8048357 * @summary PKCS8 Standards Conformance Tests + * @library /test/lib * @requires (os.family != "solaris") * @modules java.base/sun.security.pkcs * java.base/sun.security.util @@ -42,18 +43,16 @@ import java.math.BigInteger; import java.security.InvalidKeyException; import java.util.Arrays; -import sun.security.util.HexDumpEncoder; import sun.security.pkcs.PKCS8Key; import sun.security.provider.DSAPrivateKey; import sun.security.util.DerOutputStream; import sun.security.util.DerValue; import sun.security.x509.AlgorithmId; +import jdk.test.lib.hexdump.HexPrinter; import static java.lang.System.out; public class PKCS8Test { - static final HexDumpEncoder hexDump = new HexDumpEncoder(); - static final DerOutputStream derOutput = new DerOutputStream(); static final String FORMAT = "PKCS#8"; @@ -281,6 +280,6 @@ public static void main(String[] args) static void dumpByteArray(String nm, byte[] bytes) throws IOException { out.println(nm + " length: " + bytes.length); - hexDump.encodeBuffer(bytes, out); + HexPrinter.simple().dest(out).format(bytes); } } diff --git a/test/jdk/sun/security/pkcs/pkcs9/UnknownAttribute.java b/test/jdk/sun/security/pkcs/pkcs9/UnknownAttribute.java index dbac0ca772f..333550d2ace 100644 --- a/test/jdk/sun/security/pkcs/pkcs9/UnknownAttribute.java +++ b/test/jdk/sun/security/pkcs/pkcs9/UnknownAttribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2020, 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 @@ -25,6 +25,7 @@ * @test * @bug 8011867 8242151 * @summary Accept unknown PKCS #9 attributes + * @library /test/lib * @modules java.base/sun.security.pkcs * java.base/sun.security.util */ @@ -32,10 +33,10 @@ import java.io.*; import java.util.Arrays; -import sun.security.util.HexDumpEncoder; import sun.security.pkcs.PKCS9Attribute; import sun.security.util.DerValue; import sun.security.util.ObjectIdentifier; +import jdk.test.lib.hexdump.HexPrinter; public class UnknownAttribute { @@ -58,7 +59,7 @@ public static void main(String[] args) throws Exception { } ByteArrayOutputStream bout = new ByteArrayOutputStream(); p2.derEncode(bout); - new HexDumpEncoder().encodeBuffer(bout.toByteArray(), System.err); + HexPrinter.simple().dest(System.err).format(bout.toByteArray()); if (!Arrays.equals(data, bout.toByteArray())) { throw new Exception(); } diff --git a/test/jdk/sun/security/pkcs11/KeyStore/Basic.java b/test/jdk/sun/security/pkcs11/KeyStore/Basic.java index 56755e07103..f63419b97b1 100644 --- a/test/jdk/sun/security/pkcs11/KeyStore/Basic.java +++ b/test/jdk/sun/security/pkcs11/KeyStore/Basic.java @@ -58,6 +58,8 @@ import com.sun.security.auth.module.*; import com.sun.security.auth.callback.*; +import jtreg.SkippedException; +import org.testng.SkipException; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -113,7 +115,11 @@ public void setUp() throws Exception { @Test public void testBasic() throws Exception { String[] args = {"sm", "Basic.policy"}; - main(new Basic(), args); + try { + main(new Basic(), args); + } catch (SkippedException se) { + throw new SkipException("One or more tests are skipped"); + } } private static class FooEntry implements KeyStore.Entry { } diff --git a/test/jdk/sun/security/pkcs11/KeyStore/ClientAuth.java b/test/jdk/sun/security/pkcs11/KeyStore/ClientAuth.java index 5c609b26fd3..1af1258d173 100644 --- a/test/jdk/sun/security/pkcs11/KeyStore/ClientAuth.java +++ b/test/jdk/sun/security/pkcs11/KeyStore/ClientAuth.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, 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 @@ -29,6 +29,8 @@ * @run testng/othervm ClientAuth */ +import jtreg.SkippedException; +import org.testng.SkipException; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -119,7 +121,11 @@ public void testClientAuthTLSv12AndCipherSuite() throws Exception { private void runTest(String[] args) throws Exception { System.out.println("Running with args: " + Arrays.toString(args)); parseArguments(args); - main(new ClientAuth()); + try { + main(new ClientAuth()); + } catch (SkippedException se) { + throw new SkipException("One or more tests are skipped"); + } } /* @@ -383,6 +389,10 @@ void startClient (boolean newThread) { * Our client thread just died. */ System.err.println("Client died..."); + // if the exception is thrown before connecting to the + // server, the test will time out and the exception will + // be lost/hidden. + e.printStackTrace(System.err); clientException = e; } }); diff --git a/test/jdk/sun/security/pkcs11/KeyStore/SecretKeysBasic.java b/test/jdk/sun/security/pkcs11/KeyStore/SecretKeysBasic.java index 741a38995ae..4d876604c01 100644 --- a/test/jdk/sun/security/pkcs11/KeyStore/SecretKeysBasic.java +++ b/test/jdk/sun/security/pkcs11/KeyStore/SecretKeysBasic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2023, 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 @@ -26,6 +26,8 @@ * @library /test/lib .. * @run testng/othervm SecretKeysBasic */ +import jtreg.SkippedException; +import org.testng.SkipException; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -62,7 +64,11 @@ public void setUp() throws Exception { @Test public void testBasic() throws Exception { - main(new SecretKeysBasic()); + try { + main(new SecretKeysBasic()); + } catch (SkippedException se) { + throw new SkipException("One or more tests are skipped"); + } } public void main(Provider p) throws Exception { diff --git a/test/jdk/sun/security/pkcs11/PKCS11Test.java b/test/jdk/sun/security/pkcs11/PKCS11Test.java index b14daf6c6d7..1c0c8d6dcad 100644 --- a/test/jdk/sun/security/pkcs11/PKCS11Test.java +++ b/test/jdk/sun/security/pkcs11/PKCS11Test.java @@ -48,7 +48,6 @@ import java.security.spec.ECParameterSpec; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -57,31 +56,51 @@ import java.util.ServiceConfigurationError; import java.util.ServiceLoader; import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import jdk.test.lib.Platform; import jdk.test.lib.artifacts.Artifact; import jdk.test.lib.artifacts.ArtifactResolver; import jdk.test.lib.artifacts.ArtifactResolverException; +import jtreg.SkippedException; public abstract class PKCS11Test { - private boolean enableSM = false; - static final Properties props = System.getProperties(); - static final String PKCS11 = "PKCS11"; - // directory of the test source static final String BASE = System.getProperty("test.src", "."); - static final String TEST_CLASSES = System.getProperty("test.classes", "."); - static final char SEP = File.separatorChar; - private static final String DEFAULT_POLICY = - BASE + SEP + ".." + SEP + "policy"; + // Version of the NSS artifact. This coincides with the version of + // the NSS version + private static final String NSS_BUNDLE_VERSION = "3.91"; + private static final String NSSLIB = "jpg.tests.jdk.nsslib"; // directory corresponding to BASE in the /closed hierarchy static final String CLOSED_BASE; + private static final String DEFAULT_POLICY = BASE + SEP + ".." + SEP + "policy"; + private static final String PKCS11_REL_PATH = "sun/security/pkcs11"; + private static final char[] HEX_DIGITS = "0123456789abcdef".toCharArray(); + + static double nss_version = -1; + static ECCState nss_ecc_status = ECCState.Basic; + + // The NSS library we need to search for in getNSSLibDir() + // Default is "libsoftokn3.so", listed as "softokn3" + // The other is "libnss3.so", listed as "nss3". + static String nss_library = "softokn3"; + + // NSS versions of each library. It is simpler to keep nss_version + // for quick checking for generic testing than many if-else statements. + static double softoken3_version = -1; + static double nss3_version = -1; + static Provider pkcs11 = newPKCS11Provider(); + private static String PKCS11_BASE; + private static Map osMap; static { // hack @@ -96,21 +115,15 @@ public abstract class PKCS11Test { System.setProperty("closed.base", CLOSED_BASE); } - // NSS version info - public static enum ECCState { None, Basic, Extended }; - static double nss_version = -1; - static ECCState nss_ecc_status = ECCState.Extended; - - // The NSS library we need to search for in getNSSLibDir() - // Default is "libsoftokn3.so", listed as "softokn3" - // The other is "libnss3.so", listed as "nss3". - static String nss_library = "softokn3"; + static { + try { + PKCS11_BASE = getBase(); + } catch (Exception e) { + // ignore + } + } - // NSS versions of each library. It is simplier to keep nss_version - // for quick checking for generic testing than many if-else statements. - static double softoken3_version = -1; - static double nss3_version = -1; - static Provider pkcs11 = newPKCS11Provider(); + private boolean enableSM = false; // Utility methods // Used to backport HexFormat from 17. @@ -147,7 +160,7 @@ protected static String toHexString(byte[] block) { } public static Provider newPKCS11Provider() { - ServiceLoader sl = ServiceLoader.load(java.security.Provider.class); + ServiceLoader sl = ServiceLoader.load(java.security.Provider.class); Iterator iter = sl.iterator(); Provider p = null; boolean found = false; @@ -165,8 +178,8 @@ public static Provider newPKCS11Provider() { // Nothing found through ServiceLoader; fall back to reflection if (!found) { try { - Class clazz = Class.forName("sun.security.pkcs11.SunPKCS11"); - p = (Provider) clazz.newInstance(); + Class clazz = Class.forName("sun.security.pkcs11.SunPKCS11"); + p = (Provider) clazz.getDeclaredConstructor().newInstance(); } catch (Exception ex) { ex.printStackTrace(); } @@ -200,38 +213,6 @@ static Provider getSunPKCS11(String config, Provider p) throws Exception { return p.configure(config); } - public abstract void main(Provider p) throws Exception; - - protected boolean skipTest(Provider p) { - return false; - } - - private void premain(Provider p) throws Exception { - if (skipTest(p)) { - return; - } - - // set a security manager and policy before a test case runs, - // and disable them after the test case finished - try { - if (enableSM) { - System.setSecurityManager(new SecurityManager()); - } - long start = System.currentTimeMillis(); - System.out.printf( - "Running test with provider %s (security manager %s) ...%n", - p.getName(), enableSM ? "enabled" : "disabled"); - main(p); - long stop = System.currentTimeMillis(); - System.out.println("Completed test with provider " + p.getName() + - " (" + (stop - start) + " ms)."); - } finally { - if (enableSM) { - System.setSecurityManager(null); - } - } - } - public static void main(PKCS11Test test) throws Exception { main(test, null); } @@ -256,9 +237,39 @@ public static void main(PKCS11Test test, String[] args) throws Exception { Provider[] oldProviders = Security.getProviders(); try { System.out.println("Beginning test run " + test.getClass().getName() + "..."); - testDefault(test); - testNSS(test); - testDeimos(test); + boolean skippedDefault = false; + boolean skippedNSS = false; + boolean skippedDeimos = false; + + // Use separate try-catch for each test to allow all test run + try { + testDefault(test); + } catch (SkippedException se) { + System.out.println("testDefault: Skipped"); + skippedDefault = true; + se.printStackTrace(System.out); + } + + try { + testNSS(test); + } catch (SkippedException se) { + System.out.println("testNSS: Skipped"); + skippedNSS = true; + se.printStackTrace(System.out); + } + + try { + testDeimos(test); + } catch (SkippedException se) { + System.out.println("testDeimos: Skipped"); + skippedDeimos = true; + se.printStackTrace(System.out); + } + + if (skippedDefault && skippedNSS && skippedDeimos) { + throw new SkippedException("All tests are skipped, check logs"); + } + } finally { // NOTE: Do not place a 'return' in any finally block // as it will suppress exceptions and hide test failures. @@ -268,7 +279,7 @@ public static void main(PKCS11Test test, String[] args) throws Exception { // useful for ./Provider/Login.sh, where a SecurityManager exists. if (oldProviders.length == newProviders.length) { found = false; - for (int i = 0; i testDeimos: Starting test run"); + if ("true".equals(System.getProperty("NO_DEIMOS"))) { + System.out.println("Skip Deimos software as test configured with NO_DEIMOS"); return; } + + if (!new File("/opt/SUNWconn/lib/libpkcs11.so").isFile()) { + throw new SkippedException("testDeimos: \"/opt/SUNWconn/lib/libpkcs11.so\" " + + "file required for Deimos not found"); + } + String base = getBase(); String p11config = base + SEP + "nss" + SEP + "p11-deimos.txt"; Provider p = getSunPKCS11(p11config); test.premain(p); + System.out.println("testDeimos: Completed"); } + // Run test for default configured PKCS11 providers (if any) public static void testDefault(PKCS11Test test) throws Exception { - // run test for default configured PKCS11 providers (if any) + System.out.println("===> testDefault: Starting test run"); + boolean foundPKCS11 = false; if ("true".equals(System.getProperty("NO_DEFAULT"))) { + System.out.println("Skip default provider as test configured with NO_DEFAULT"); return; } Provider[] providers = Security.getProviders(); - for (int i = 0; i < providers.length; i++) { - Provider p = providers[i]; + for (Provider p : providers) { if (p.getName().startsWith("SunPKCS11-")) { + foundPKCS11 = true; test.premain(p); } } - } - private static String PKCS11_BASE; - static { - try { - PKCS11_BASE = getBase(); - } catch (Exception e) { - // ignore + if (!foundPKCS11) { + throw new SkippedException("testDefault: Skip default test as SunPKCS11 " + + "provider is not configured"); } - } - private final static String PKCS11_REL_PATH = "sun/security/pkcs11"; + System.out.println("testDefault: Completed"); + } public static String getBase() throws Exception { if (PKCS11_BASE != null) { @@ -336,7 +354,7 @@ public static String getBase() throws Exception { } cwd = cwd.getParentFile(); if (cwd == null) { - throw new Exception("Test root directory not found"); + throw new RuntimeException("Test root directory not found"); } } PKCS11_BASE = new File(cwd, PKCS11_REL_PATH.replace('/', SEP)).getAbsolutePath(); @@ -365,30 +383,19 @@ private static Path getNSSLibPath() throws Exception { static Path getNSSLibPath(String library) throws Exception { String osid = getOsId(); - String[] nssLibDirs = getNssLibPaths(osid); - if (nssLibDirs == null) { - System.out.println("Warning: unsupported OS: " + osid - + ", please initialize NSS librarys location firstly, skipping test"); - return null; - } - if (nssLibDirs.length == 0) { - System.out.println("Warning: NSS not supported on this platform, skipping test"); - return null; + String nssLibDir = fetchNssLib(osid); + if (nssLibDir == null) { + throw new SkippedException("Warning: unsupported OS: " + osid + + ", please initialize NSS library location, skipping test"); } - Path nssLibPath = null; - for (String dir : nssLibDirs) { - Path libPath = Paths.get(dir).resolve(System.mapLibraryName(library)); - if (Files.exists(libPath)) { - nssLibPath = libPath; - break; - } + String libraryName = System.mapLibraryName(library); + Path libPath = Paths.get(nssLibDir).resolve(libraryName); + if (!Files.exists(libPath)) { + throw new SkippedException("NSS library \"" + libraryName + "\" was not found in " + nssLibDir); } - if (nssLibPath == null) { - System.out.println("Warning: can't find NSS librarys on this machine, skipping test"); - return null; - } - return nssLibPath; + + return libPath; } private static String getOsId() { @@ -398,9 +405,8 @@ private static String getOsId() { } else if (osName.equals("Mac OS X")) { osName = "MacOSX"; } - String osid = osName + "-" + props.getProperty("os.arch") + "-" + return osName + "-" + props.getProperty("os.arch") + "-" + props.getProperty("sun.arch.data.model"); - return osid; } static boolean isBadNSSVersion(Provider p) { @@ -413,7 +419,7 @@ static boolean isBadNSSVersion(Provider p) { return false; } - protected static void safeReload(String lib) throws Exception { + protected static void safeReload(String lib) { try { System.load(lib); } catch (UnsatisfiedLinkError e) { @@ -423,11 +429,9 @@ protected static void safeReload(String lib) throws Exception { } } - static boolean loadNSPR(String libdir) throws Exception { + static boolean loadNSPR(String libdir) { // load NSS softoken dependencies in advance to avoid resolver issues - String dir = libdir.endsWith(File.separator) - ? libdir - : libdir + File.separator; + String dir = libdir.endsWith(File.separator) ? libdir : libdir + File.separator; safeReload(dir + System.mapLibraryName("nspr4")); safeReload(dir + System.mapLibraryName("plc4")); safeReload(dir + System.mapLibraryName("plds4")); @@ -438,7 +442,7 @@ static boolean loadNSPR(String libdir) throws Exception { // Check the provider being used is NSS public static boolean isNSS(Provider p) { - return p.getName().toUpperCase().equals("SUNPKCS11-NSS"); + return p.getName().equalsIgnoreCase("SUNPKCS11-NSS"); } static double getNSSVersion() { @@ -534,25 +538,25 @@ static double getNSSInfo(String library) { // the index after whitespace after nssHeader int afterheader = s.indexOf("NSS", i) + 4; - String version = String.valueOf(s.charAt(afterheader)); + StringBuilder version = new StringBuilder(String.valueOf(s.charAt(afterheader))); for (char c = s.charAt(++afterheader); - c == '.' || (c >= '0' && c <= '9'); - c = s.charAt(++afterheader)) { - version += c; + c == '.' || (c >= '0' && c <= '9'); + c = s.charAt(++afterheader)) { + version.append(c); } // If a "dot dot" release, strip the extra dots for double parsing - String[] dot = version.split("\\."); + String[] dot = version.toString().split("\\."); if (dot.length > 2) { - version = dot[0]+"."+dot[1]; + version = new StringBuilder(dot[0] + "." + dot[1]); for (int j = 2; dot.length > j; j++) { - version += dot[j]; + version.append(dot[j]); } } // Convert to double for easier version value checking try { - nss_version = Double.parseDouble(version); + nss_version = Double.parseDouble(version.toString()); } catch (NumberFormatException e) { System.out.println("===== Content start ====="); System.out.println(s); @@ -562,7 +566,7 @@ static double getNSSInfo(String library) { e.printStackTrace(); } - System.out.print("lib" + library + " version = "+version+". "); + System.out.print("library: " + library + ", version: " + version + ". "); // Check for ECC if (s.indexOf("Basic") > 0) { @@ -591,13 +595,15 @@ public static void useNSS() { // Run NSS testing on a Provider p configured with test nss config public static void testNSS(PKCS11Test test) throws Exception { + System.out.println("===> testNSS: Starting test run"); String nssConfig = getNssConfig(); if (nssConfig == null) { - // issue loading libraries - return; + throw new SkippedException("testNSS: Problem loading NSS libraries"); } + Provider p = getSunPKCS11(nssConfig); test.premain(p); + System.out.println("testNSS: Completed"); } public static String getNssConfig() throws Exception { @@ -606,7 +612,7 @@ public static String getNssConfig() throws Exception { return null; } - if (loadNSPR(libdir) == false) { + if (!loadNSPR(libdir)) { return null; } @@ -644,12 +650,12 @@ static List getKnownCurves(Provider p) throws Exception { if (kcProp == null) { throw new RuntimeException( - "\"AlgorithmParameters.EC SupportedCurves property\" not found"); + "\"AlgorithmParameters.EC SupportedCurves property\" not found"); } System.out.println("Finding supported curves using list from SunEC\n"); index = 0; - for (;;) { + for (; ; ) { // Each set of curve names is enclosed with brackets. begin = kcProp.indexOf('[', index); end = kcProp.indexOf(']', index); @@ -666,12 +672,12 @@ static List getKnownCurves(Provider p) throws Exception { end = kcProp.indexOf(',', begin); if (end == -1) { // Only one name in the set. - end = index -1; + end = index - 1; } curve = kcProp.substring(begin, end); getSupportedECParameterSpec(curve, p) - .ifPresent(spec -> results.add(spec)); + .ifPresent(spec -> results.add(spec)); } if (results.size() == 0) { @@ -682,9 +688,9 @@ static List getKnownCurves(Provider p) throws Exception { } static Optional getSupportedECParameterSpec(String curve, - Provider p) throws Exception { + Provider p) throws Exception { ECParameterSpec e = getECParameterSpec(p, curve); - System.out.print("\t "+ curve + ": "); + System.out.print("\t " + curve + ": "); try { KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", p); kpg.initialize(e); @@ -706,97 +712,13 @@ private static ECParameterSpec getECParameterSpec(Provider p, String name) throws Exception { AlgorithmParameters parameters = - AlgorithmParameters.getInstance("EC", p); + AlgorithmParameters.getInstance("EC", p); parameters.init(new ECGenParameterSpec(name)); return parameters.getParameterSpec(ECParameterSpec.class); } - // Check support for a curve with a provided Vector of EC support - boolean checkSupport(List supportedEC, - ECParameterSpec curve) { - for (ECParameterSpec ec: supportedEC) { - if (ec.equals(curve)) { - return true; - } - } - return false; - } - - private static Map osMap; - - // Location of the NSS libraries on each supported platform - private static Map getOsMap() { - if (osMap != null) { - return osMap; - } - - osMap = new HashMap<>(); - osMap.put("SunOS-sparc-32", new String[] { "/usr/lib/mps/" }); - osMap.put("SunOS-sparcv9-64", new String[] { "/usr/lib/mps/64/" }); - osMap.put("SunOS-x86-32", new String[] { "/usr/lib/mps/" }); - osMap.put("SunOS-amd64-64", new String[] { "/usr/lib/mps/64/" }); - osMap.put("Linux-i386-32", new String[] { - "/usr/lib/i386-linux-gnu/", - "/usr/lib32/", - "/usr/lib/" }); - osMap.put("Linux-amd64-64", new String[] { - "/usr/lib/x86_64-linux-gnu/", - "/usr/lib/x86_64-linux-gnu/nss/", - "/usr/lib64/" }); - osMap.put("Linux-ppc64-64", new String[] { "/usr/lib64/" }); - osMap.put("Linux-ppc64le-64", new String[] { "/usr/lib64/" }); - osMap.put("Linux-s390x-64", new String[] { "/usr/lib64/" }); - osMap.put("Windows-x86-32", new String[] {}); - osMap.put("Windows-amd64-64", new String[] {}); - osMap.put("MacOSX-x86_64-64", new String[] {}); - osMap.put("Linux-arm-32", new String[] { - "/usr/lib/arm-linux-gnueabi/nss/", - "/usr/lib/arm-linux-gnueabihf/nss/" }); - // Exclude linux-aarch64 at the moment until the following bug is fixed: - // 8296631: NSS tests failing on OL9 linux-aarch64 hosts -// osMap.put("Linux-aarch64-64", new String[] { -// "/usr/lib/aarch64-linux-gnu/", -// "/usr/lib/aarch64-linux-gnu/nss/", -// "/usr/lib64/" }); - return osMap; - } - - private static String[] getNssLibPaths(String osId) { - String[] preferablePaths = getPreferableNssLibPaths(osId); - if (preferablePaths.length != 0) { - return preferablePaths; - } else { - return getOsMap().get(osId); - } - } - - private static String[] getPreferableNssLibPaths(String osId) { - List nssLibPaths = new ArrayList<>(); - - String customNssLibPaths = System.getProperty("test.nss.lib.paths"); - if (customNssLibPaths == null) { - // If custom local NSS lib path is not provided, - // try to download NSS libs from artifactory - String path = fetchNssLib(osId); - if (path != null) { - nssLibPaths.add(path); - } - } else { - String[] paths = customNssLibPaths.split(","); - for (String path : paths) { - if (!path.endsWith(File.separator)) { - nssLibPaths.add(path + File.separator); - } else { - nssLibPaths.add(path); - } - } - } - - return nssLibPaths.toArray(new String[nssLibPaths.size()]); - } - private final static char[] hexDigits = "0123456789abcdef".toCharArray(); private static final String distro = distro(); @@ -817,8 +739,8 @@ public static String toString(byte[] b) { if (i != 0) { sb.append(':'); } - sb.append(hexDigits[k >>> 4]); - sb.append(hexDigits[k & 0xf]); + sb.append(HEX_DIGITS[k >>> 4]); + sb.append(HEX_DIGITS[k & 0xf]); } return sb.toString(); } @@ -864,20 +786,11 @@ private static int nextNibble(StringReader r) throws IOException { } } - T[] concat(T[] a, T[] b) { - if ((b == null) || (b.length == 0)) { - return a; - } - T[] r = Arrays.copyOf(a, a.length + b.length); - System.arraycopy(b, 0, r, a.length, b.length); - return r; - } - /** * Returns supported algorithms of specified type. */ static List getSupportedAlgorithms(String type, String alg, - Provider p) { + Provider p) { // prepare a list of supported algorithms List algorithms = new ArrayList<>(); Set services = p.getServices(); @@ -915,7 +828,7 @@ private static String distro() { static byte[] generateData(int length) { byte data[] = new byte[length]; - for (int i=0; i clazz) { String path = null; try { path = ArtifactResolver.resolve(clazz).entrySet().stream() - .findAny().get().getValue() + File.separator + "nsslib" - + File.separator; + .findAny().get().getValue() + File.separator + "nss" + + File.separator + "lib" + File.separator; } catch (ArtifactResolverException e) { Throwable cause = e.getCause(); if (cause == null) { @@ -960,6 +883,58 @@ private static String fetchNssLib(Class clazz) { return path; } + public abstract void main(Provider p) throws Exception; + + protected boolean skipTest(Provider p) { + return false; + } + + private void premain(Provider p) throws Exception { + if (skipTest(p)) { + return; + } + + // set a security manager and policy before a test case runs, + // and disable them after the test case finished + try { + if (enableSM) { + System.setSecurityManager(new SecurityManager()); + } + long start = System.currentTimeMillis(); + System.out.printf( + "Running test with provider %s (security manager %s) ...%n", + p.getName(), enableSM ? "enabled" : "disabled"); + main(p); + long stop = System.currentTimeMillis(); + System.out.println("Completed test with provider " + p.getName() + + " (" + (stop - start) + " ms)."); + } finally { + if (enableSM) { + System.setSecurityManager(null); + } + } + } + + // Check support for a curve with a provided Vector of EC support + boolean checkSupport(List supportedEC, + ECParameterSpec curve) { + for (ECParameterSpec ec : supportedEC) { + if (ec.equals(curve)) { + return true; + } + } + return false; + } + + T[] concat(T[] a, T[] b) { + if ((b == null) || (b.length == 0)) { + return a; + } + T[] r = Arrays.copyOf(a, a.length + b.length); + System.arraycopy(b, 0, r, a.length, b.length); + return r; + } + protected void setCommonSystemProps() { System.setProperty("java.security.debug", "true"); System.setProperty("NO_DEIMOS", "true"); @@ -985,31 +960,46 @@ protected void copyNssCertKeyToClassesDir(Path dbPath) throws IOException { StandardCopyOption.REPLACE_EXISTING); } + // NSS version info + public static enum ECCState {None, Basic, Extended} + @Artifact( - organization = "jpg.tests.jdk.nsslib", + organization = NSSLIB, name = "nsslib-windows_x64", - revision = "3.46-VS2017", + revision = NSS_BUNDLE_VERSION, extension = "zip") - private static class WINDOWS_X64 { } + private static class WINDOWS_X64 { + } @Artifact( - organization = "jpg.tests.jdk.nsslib", - name = "nsslib-windows_x86", - revision = "3.46-VS2017", + organization = NSSLIB, + name = "nsslib-macosx_x64", + revision = NSS_BUNDLE_VERSION, extension = "zip") - private static class WINDOWS_X86 { } + private static class MACOSX_X64 { + } @Artifact( - organization = "jpg.tests.jdk.nsslib", - name = "nsslib-macosx_x64", - revision = "3.46", + organization = NSSLIB, + name = "nsslib-macosx_aarch64", + revision = NSS_BUNDLE_VERSION, extension = "zip") - private static class MACOSX_X64 { } + private static class MACOSX_AARCH64 { + } @Artifact( - organization = "jpg.tests.jdk.nsslib", + organization = NSSLIB, name = "nsslib-linux_x64", - revision = "3.46", + revision = NSS_BUNDLE_VERSION, + extension = "zip") + private static class LINUX_X64 { + } + + @Artifact( + organization = NSSLIB, + name = "nsslib-linux_aarch64", + revision = NSS_BUNDLE_VERSION, extension = "zip") - private static class LINUX_X64 { } + private static class LINUX_AARCH64{ + } } diff --git a/test/jdk/sun/security/pkcs11/Provider/ConfigQuotedString.java b/test/jdk/sun/security/pkcs11/Provider/ConfigQuotedString.java index 24340647d1c..a6c2a9728e0 100644 --- a/test/jdk/sun/security/pkcs11/Provider/ConfigQuotedString.java +++ b/test/jdk/sun/security/pkcs11/Provider/ConfigQuotedString.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2023, 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 @@ -28,6 +28,8 @@ * @run testng/othervm ConfigQuotedString */ +import jtreg.SkippedException; +import org.testng.SkipException; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -44,7 +46,11 @@ public void setUp() throws Exception { @Test public void testQuotedString() throws Exception { - main(new ConfigQuotedString()); + try { + main(new ConfigQuotedString()); + } catch (SkippedException se) { + throw new SkipException("One or more tests are skipped"); + } } public void main(Provider p) throws Exception { diff --git a/test/jdk/sun/security/pkcs11/Provider/Login.java b/test/jdk/sun/security/pkcs11/Provider/Login.java index 6d7063f2082..8bb39fe4906 100644 --- a/test/jdk/sun/security/pkcs11/Provider/Login.java +++ b/test/jdk/sun/security/pkcs11/Provider/Login.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, 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 @@ -28,6 +28,8 @@ * @run testng/othervm Login */ +import jtreg.SkippedException; +import org.testng.SkipException; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -55,7 +57,11 @@ public void setUp() throws Exception { @Test public void testLogin() throws Exception { String[] args = new String[]{ "sm", "Login.policy"}; - main(new Login(), args); + try { + main(new Login(), args); + } catch (SkippedException se) { + throw new SkipException("One or more tests are skipped"); + } } public void main(Provider p) throws Exception { diff --git a/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.java b/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.java index 353a5b99a64..855abe50e7b 100644 --- a/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.java +++ b/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2023, 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 @@ -21,6 +21,7 @@ * questions. */ + import sun.security.pkcs11.SunPKCS11; import javax.security.auth.Subject; @@ -32,12 +33,10 @@ import java.io.IOException; import java.lang.ref.WeakReference; import java.security.*; -import java.util.Iterator; import java.util.PropertyPermission; -import java.util.ServiceConfigurationError; -import java.util.ServiceLoader; import jdk.test.lib.util.ForceGC; +import jtreg.SkippedException; public class MultipleLogins { private static final String KS_TYPE = "PKCS11"; @@ -47,7 +46,13 @@ public class MultipleLogins { static final Policy DEFAULT_POLICY = Policy.getPolicy(); public static void main(String[] args) throws Exception { - String nssConfig = PKCS11Test.getNssConfig(); + String nssConfig = null; + try { + nssConfig = PKCS11Test.getNssConfig(); + } catch (SkippedException exc) { + System.out.println("Skipping test: " + exc.getMessage()); + } + if (nssConfig == null) { // No test framework support yet. Ignore System.out.println("No NSS config found. Skipping."); diff --git a/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.sh b/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.sh index 1e40fcfe981..c768834da7f 100644 --- a/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.sh +++ b/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.sh @@ -1,5 +1,5 @@ # -# Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2021, 2023, 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 @@ -26,6 +26,7 @@ # @summary # @library /test/lib/ # @build jdk.test.lib.util.ForceGC +# jdk.test.lib.Platform # @run shell MultipleLogins.sh # set a few environment variables so that the shell-script can run stand-alone @@ -111,6 +112,7 @@ ${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \ --add-modules jdk.crypto.cryptoki \ --add-exports jdk.crypto.cryptoki/sun.security.pkcs11=ALL-UNNAMED \ ${TESTSRC}${FS}..${FS}..${FS}..${FS}..${FS}..${FS}lib${FS}jdk${FS}test${FS}lib${FS}artifacts${FS}*.java \ + ${TESTSRC}${FS}..${FS}..${FS}..${FS}..${FS}..${FS}lib${FS}jtreg${FS}*.java \ ${TESTSRC}${FS}MultipleLogins.java \ ${TESTSRC}${FS}..${FS}PKCS11Test.java diff --git a/test/jdk/sun/security/pkcs11/README b/test/jdk/sun/security/pkcs11/README index 31efd034501..9b4c39dd41c 100644 --- a/test/jdk/sun/security/pkcs11/README +++ b/test/jdk/sun/security/pkcs11/README @@ -4,14 +4,15 @@ perform as a result of bugs or features in NSS or other pkcs11 libraries. - How to get NSS libraries? The libraries come from the following sources. -1. Specified by system property test.nss.lib.paths -System property test.nss.lib.paths can specify a set of absolute paths to -the local NSS library directories. The paths are separated by comma. +1. Specified by system property jdk.test.lib.artifacts. +The system property, jdk.test.lib.artifacts., can specify an absolute path +to the local NSS library directory. The component should be replaced with +the name element of the appropriate @Artifact class. +(See `test/jdk/sun/security/pkcs11/PKCS11Test.java`) 2. Pre-built NSS libraries from artifactory server -If the value of system property test.nss.lib.paths is not set, the tests will try -to download pre-built NSS libraries from artifactory server. Currently, the -tests only looks for libraries for Windows and MacOSX platforms on artifactory. +If the value of system property jdk.test.lib.artifacts. is not set, the +tests will try to download pre-built NSS libraries from artifactory server. Please note that JIB jar MUST be present in classpath when downloading the libraries. diff --git a/test/jdk/sun/security/pkcs11/SecmodTest.java b/test/jdk/sun/security/pkcs11/SecmodTest.java index 6ff6dd29acd..c5a01b0a739 100644 --- a/test/jdk/sun/security/pkcs11/SecmodTest.java +++ b/test/jdk/sun/security/pkcs11/SecmodTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2023, 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 @@ -24,6 +24,8 @@ // common infrastructure for Secmod tests +import jtreg.SkippedException; + import java.io.*; import java.security.Provider; @@ -43,13 +45,11 @@ static void useSqlite(boolean b) { static boolean initSecmod() throws Exception { useNSS(); LIBPATH = getNSSLibDir(); - if (LIBPATH == null) { - return false; - } // load all the libraries except libnss3 into memory - if (loadNSPR(LIBPATH) == false) { - return false; + if ((LIBPATH == null) || (!loadNSPR(LIBPATH))) { + throw new SkippedException("Failed to load NSS libraries"); } + safeReload(LIBPATH + System.mapLibraryName("softokn3")); safeReload(LIBPATH + System.mapLibraryName("nssckbi")); diff --git a/test/jdk/sun/security/pkcs11/SecureRandom/Basic.java b/test/jdk/sun/security/pkcs11/SecureRandom/Basic.java index 381efb68942..3518b628f13 100644 --- a/test/jdk/sun/security/pkcs11/SecureRandom/Basic.java +++ b/test/jdk/sun/security/pkcs11/SecureRandom/Basic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2023, 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 diff --git a/test/jdk/sun/security/ssl/SSLContextImpl/SSLContextDefault.java b/test/jdk/sun/security/ssl/SSLContextImpl/SSLContextDefault.java index b0327d69a66..7a790e72a1e 100644 --- a/test/jdk/sun/security/ssl/SSLContextImpl/SSLContextDefault.java +++ b/test/jdk/sun/security/ssl/SSLContextImpl/SSLContextDefault.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, 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 @@ -28,8 +28,9 @@ /* * @test - * @bug 8202343 - * @summary Check that SSLv3, TLSv1 and TLSv1.1 are disabled by default + * @bug 8202343 8256660 + * @summary Check that SSLv3, TLSv1, TLSv1.1, and DTLSv1.0 are disabled + * by default * @run main/othervm SSLContextDefault */ @@ -38,26 +39,43 @@ public class SSLContextDefault { - private final static String[] protocols = { + private static final String[] tlsProtocols = { "", "SSL", "TLS", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3" }; - private final static List disabledProtocols = List.of( + private static final String[] dtlsProtocols = { + "DTLS", "DTLSv1.0", "DTLSv1.2" + }; + + private static final List disabledTlsProtocols = List.of( "SSLv3", "TLSv1", "TLSv1.1" ); + private static final List disabledDtlsProtocols = List.of( + "DTLSv1.0" + ); + public static void main(String[] args) throws Exception { - for (String protocol : protocols) { - System.out.println("//"); - System.out.println("// " + "Testing for SSLContext of " + - (protocol.isEmpty() ? "" : protocol)); - System.out.println("//"); - checkForProtocols(protocol); - System.out.println(); + for (String tlsProtocol : tlsProtocols) { + testProtocol(tlsProtocol, disabledTlsProtocols); + } + for (String dtlsProtocol : dtlsProtocols) { + testProtocol(dtlsProtocol, disabledDtlsProtocols); } } - public static void checkForProtocols(String protocol) throws Exception { + private static void testProtocol(String protocol, + List disabledProtocols) throws Exception { + System.out.println("//"); + System.out.println("// " + "Testing for SSLContext of " + + (protocol.isEmpty() ? "" : protocol)); + System.out.println("//"); + checkForProtocols(protocol, disabledProtocols); + System.out.println(); + } + + private static void checkForProtocols(String protocol, + List disabledProtocols) throws Exception { SSLContext context; if (protocol.isEmpty()) { context = SSLContext.getDefault(); @@ -68,32 +86,35 @@ public static void checkForProtocols(String protocol) throws Exception { // check for the presence of supported protocols of SSLContext SSLParameters parameters = context.getSupportedSSLParameters(); - checkProtocols(parameters.getProtocols(), + checkProtocols(parameters.getProtocols(), disabledProtocols, "Supported protocols in SSLContext", false); - // check for the presence of default protocols of SSLContext parameters = context.getDefaultSSLParameters(); - checkProtocols(parameters.getProtocols(), + checkProtocols(parameters.getProtocols(), disabledProtocols, "Enabled protocols in SSLContext", true); // check for the presence of supported protocols of SSLEngine SSLEngine engine = context.createSSLEngine(); - checkProtocols(engine.getSupportedProtocols(), + checkProtocols(engine.getSupportedProtocols(), disabledProtocols, "Supported protocols in SSLEngine", false); // Check for the presence of default protocols of SSLEngine - checkProtocols(engine.getEnabledProtocols(), + checkProtocols(engine.getEnabledProtocols(), disabledProtocols, "Enabled protocols in SSLEngine", true); + if (protocol.startsWith("DTLS")) { + return; + } + SSLSocketFactory factory = context.getSocketFactory(); try (SSLSocket socket = (SSLSocket)factory.createSocket()) { // check for the presence of supported protocols of SSLSocket - checkProtocols(socket.getSupportedProtocols(), + checkProtocols(socket.getSupportedProtocols(), disabledProtocols, "Supported cipher suites in SSLSocket", false); // Check for the presence of default protocols of SSLSocket - checkProtocols(socket.getEnabledProtocols(), + checkProtocols(socket.getEnabledProtocols(), disabledProtocols, "Enabled protocols in SSLSocket", true); } @@ -102,16 +123,19 @@ public static void checkForProtocols(String protocol) throws Exception { (SSLServerSocket)serverFactory.createServerSocket()) { // check for the presence of supported protocols of SSLServerSocket checkProtocols(serverSocket.getSupportedProtocols(), - "Supported cipher suites in SSLServerSocket", false); + disabledProtocols, "Supported cipher suites in SSLServerSocket", + false); // Check for the presence of default protocols of SSLServerSocket checkProtocols(serverSocket.getEnabledProtocols(), - "Enabled protocols in SSLServerSocket", true); + disabledProtocols, "Enabled protocols in SSLServerSocket", + true); } } private static void checkProtocols(String[] protocols, - String title, boolean disabled) throws Exception { + List disabledProtocols, String title, boolean disabled) + throws Exception { showProtocols(protocols, title); if (disabled) { diff --git a/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketKeyLimit.java b/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketKeyLimit.java index f87effe9dce..8b19d39af7e 100644 --- a/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketKeyLimit.java +++ b/test/jdk/sun/security/ssl/SSLSocketImpl/SSLSocketKeyLimit.java @@ -69,7 +69,7 @@ import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; import jdk.test.lib.Utils; -import sun.security.util.HexDumpEncoder; +import jdk.test.lib.hexdump.HexPrinter; public class SSLSocketKeyLimit { SSLSocket socket; @@ -227,7 +227,7 @@ void read(SSLSocket s) throws Exception { continue; } System.out.println("\nData invalid: " + - new HexDumpEncoder().encode(buf)); + HexPrinter.minimal().toString(buf)); break; } diff --git a/test/jdk/sun/security/tools/keytool/NssTest.java b/test/jdk/sun/security/tools/keytool/NssTest.java index bc66fdaae44..80ef41d446d 100644 --- a/test/jdk/sun/security/tools/keytool/NssTest.java +++ b/test/jdk/sun/security/tools/keytool/NssTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2023 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 @@ -56,8 +56,9 @@ private static void copyFiles() throws IOException { Path dbPath = srcPath.getParent().getParent() .resolve("pkcs11").resolve("nss").resolve("db"); - Files.copy(dbPath.resolve("cert8.db"), Paths.get("cert8.db")); - Files.copy(dbPath.resolve("key3.db"), Paths.get("key3.db")); - Files.copy(dbPath.resolve("secmod.db"), Paths.get("secmod.db")); + Path destDir = Path.of( "tmpdb"); + Files.createDirectory(destDir); + Files.copy(dbPath.resolve("cert9.db"), destDir.resolve("cert9.db")); + Files.copy(dbPath.resolve("key4.db"), destDir.resolve("key4.db")); } } diff --git a/test/jdk/sun/security/tools/keytool/p11-nss.txt b/test/jdk/sun/security/tools/keytool/p11-nss.txt index dd200a326c0..9c8ac0a43ab 100644 --- a/test/jdk/sun/security/tools/keytool/p11-nss.txt +++ b/test/jdk/sun/security/tools/keytool/p11-nss.txt @@ -6,7 +6,7 @@ slot = 2 library = ${nss.lib} -nssArgs = "configdir='.' certPrefix='' keyPrefix='' secmod='secmod.db'" +nssArgs = "configdir='sql:./tmpdb' certPrefix='' keyPrefix='' secmod='secmod.db'" #forceLogin = true diff --git a/test/jdk/sun/security/x509/X500Name/NullX500Name.java b/test/jdk/sun/security/x509/X500Name/NullX500Name.java index fe0b1d3874c..37e12d8a892 100644 --- a/test/jdk/sun/security/x509/X500Name/NullX500Name.java +++ b/test/jdk/sun/security/x509/X500Name/NullX500Name.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2020, 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 @@ -24,6 +24,7 @@ /* @test * @bug 4118818 * @summary allow null X.500 Names + * @library /test/lib * @modules java.base/sun.security.util * java.base/sun.security.x509 */ @@ -31,7 +32,7 @@ import java.util.Arrays; import sun.security.util.DerOutputStream; import sun.security.x509.*; -import sun.security.util.HexDumpEncoder; +import jdk.test.lib.hexdump.HexPrinter; public class NullX500Name { @@ -63,16 +64,16 @@ public static void main(String[] argv) throws Exception { subject.encode(dos); byte[] out = dos.toByteArray(); byte[] enc = subject.getEncoded(); - HexDumpEncoder e = new HexDumpEncoder(); + HexPrinter e = HexPrinter.simple(); if (Arrays.equals(out, enc)) - System.out.println("Sucess: out:" + e.encodeBuffer(out)); + System.out.println("Success: out:" + e.toString(out)); else { - System.out.println("Failed: encode:" + e.encodeBuffer(out)); - System.out.println("getEncoded:" + e.encodeBuffer(enc)); + System.out.println("Failed: encode:" + e.toString(out)); + System.out.println("getEncoded:" + e.toString(enc)); } X500Name x = new X500Name(enc); if (x.equals(subject)) - System.out.println("Sucess: X500Name(byte[]):" + x.toString()); + System.out.println("Success: X500Name(byte[]):" + x.toString()); else System.out.println("Failed: X500Name(byte[]):" + x.toString()); } diff --git a/test/jdk/tools/launcher/RunpathTest.java b/test/jdk/tools/launcher/RunpathTest.java index 8f761e13bff..2246587f092 100644 --- a/test/jdk/tools/launcher/RunpathTest.java +++ b/test/jdk/tools/launcher/RunpathTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, 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 @@ -24,7 +24,8 @@ /* * @test * @bug 7190813 8022719 - * @summary Check for extended RPATHs on *nixes + * @summary Check for extended RPATHs on Linux + * @requires os.family == "linux" * @compile -XDignore.symbol.file RunpathTest.java * @run main RunpathTest * @author ksrini @@ -57,25 +58,23 @@ void elfCheck(String javacmd, String expectedRpath) { final TestResult tr = doExec(elfreaderCmd, "-d", javacmd); if (!tr.matches(expectedRpath)) { System.out.println(tr); - throw new RuntimeException("FAILED: RPATH/RUNPATH strings " + + throw new RuntimeException("FAILED: RPATH strings " + expectedRpath + " not found in " + javaCmd); } - System.out.println(javacmd + " contains expected RPATHS/RUNPATH"); + System.out.println(javacmd + " contains expected RPATHS"); } void testRpath() { - String expectedRpath = ".*R(UN)?PATH.*\\$ORIGIN/../lib.*"; + String expectedRpath = ".*RPATH.*\\$ORIGIN/../lib.*"; elfCheck(javaCmd, expectedRpath); } public static void main(String... args) throws Exception { - if (isSolaris || isLinux) { - RunpathTest rp = new RunpathTest(); - if (rp.elfreaderCmd == null) { - System.err.println("Warning: test passes vacuously"); - return; - } - rp.testRpath(); + RunpathTest rp = new RunpathTest(); + if (rp.elfreaderCmd == null) { + System.err.println("Warning: test passes vacuously"); + return; } + rp.testRpath(); } } diff --git a/test/jtreg-ext/requires/VMProps.java b/test/jtreg-ext/requires/VMProps.java index 07879d44cee..c31290ac525 100644 --- a/test/jtreg-ext/requires/VMProps.java +++ b/test/jtreg-ext/requires/VMProps.java @@ -571,14 +571,15 @@ private String implementor() { * Checks if we are in almost out-of-box configuration, i.e. the flags * which JVM is started with don't affect its behavior "significantly". * {@code TEST_VM_FLAGLESS} enviroment variable can be used to force this - * method to return true and allow any flags. + * method to return true or false and allow or reject any flags. * * @return true if there are no JVM flags */ private String isFlagless() { boolean result = true; - if (System.getenv("TEST_VM_FLAGLESS") != null) { - return "" + result; + String flagless = System.getenv("TEST_VM_FLAGLESS"); + if (flagless != null) { + return "" + "true".equalsIgnoreCase(flagless); } List allFlags = new ArrayList(); diff --git a/test/langtools/TEST.ROOT b/test/langtools/TEST.ROOT index 3348f3711bc..da089df72a9 100644 --- a/test/langtools/TEST.ROOT +++ b/test/langtools/TEST.ROOT @@ -15,7 +15,7 @@ keys=intermittent randomness groups=TEST.groups # Minimum jtreg version -requiredVersion=6+1 +requiredVersion=7.3.1+1 # Use new module options useNewOptions=true diff --git a/test/langtools/jdk/javadoc/doclet/testHtmlDocument/TestHtmlDocument.java b/test/langtools/jdk/javadoc/doclet/testHtmlDocument/TestHtmlDocument.java index 27bdcfa4ce7..cab7900ddf4 100644 --- a/test/langtools/jdk/javadoc/doclet/testHtmlDocument/TestHtmlDocument.java +++ b/test/langtools/jdk/javadoc/doclet/testHtmlDocument/TestHtmlDocument.java @@ -75,31 +75,31 @@ public static String generateHtmlTree() { HtmlTree title = new HtmlTree(HtmlTag.TITLE); // String content within the document StringContent titleContent = new StringContent("Markup test"); - title.addContent(titleContent); - head.addContent(title); + title.add(titleContent); + head.add(title); // Test META tag HtmlTree meta = new HtmlTree(HtmlTag.META); - meta.addAttr(HtmlAttr.NAME, "keywords"); - meta.addAttr(HtmlAttr.CONTENT, "testContent"); - head.addContent(meta); + meta.put(HtmlAttr.NAME, "keywords"); + meta.put(HtmlAttr.CONTENT, "testContent"); + head.add(meta); // Test invalid META tag HtmlTree invmeta = new HtmlTree(HtmlTag.META); - head.addContent(invmeta); + head.add(invmeta); // Test LINK tag HtmlTree link = new HtmlTree(HtmlTag.LINK); - link.addAttr(HtmlAttr.REL, "testRel"); - link.addAttr(HtmlAttr.HREF, "testLink.html"); - head.addContent(link); + link.put(HtmlAttr.REL, "testRel"); + link.put(HtmlAttr.HREF, "testLink.html"); + head.add(link); // Test invalid LINK tag HtmlTree invlink = new HtmlTree(HtmlTag.LINK); - head.addContent(invlink); - html.addContent(head); + head.add(invlink); + html.add(head); // Comment within the document Comment bodyMarker = new Comment("======== START OF BODY ========"); - html.addContent(bodyMarker); + html.add(bodyMarker); HtmlTree body = new HtmlTree(HtmlTag.BODY); Comment pMarker = new Comment("======== START OF PARAGRAPH ========"); - body.addContent(pMarker); + body.add(pMarker); HtmlTree p = new HtmlTree(HtmlTag.P); StringContent bodyContent = new StringContent( "This document is generated from sample source code and HTML " + @@ -107,41 +107,41 @@ public static String generateHtmlTree() { "subclasses, subinterfaces, nested classes, nested interfaces," + "inheriting from other packages, constructors, fields," + "methods, and so forth. "); - p.addContent(bodyContent); + p.add(bodyContent); StringContent anchorContent = new StringContent("Click Here"); - p.addContent(HtmlTree.A("testLink.html", anchorContent)); + p.add(HtmlTree.A("testLink.html", anchorContent)); StringContent pContent = new StringContent(" to out a link."); - p.addContent(pContent); - body.addContent(p); + p.add(pContent); + body.add(p); HtmlTree p1 = new HtmlTree(HtmlTag.P); // Test another version of A tag. HtmlTree anchor = new HtmlTree(HtmlTag.A); - anchor.addAttr(HtmlAttr.HREF, "testLink.html"); - anchor.addAttr(HtmlAttr.ID, "Another version of a tag"); - p1.addContent(anchor); - body.addContent(p1); + anchor.put(HtmlAttr.HREF, "testLink.html"); + anchor.put(HtmlAttr.ID, "Another version of a tag"); + p1.add(anchor); + body.add(p1); // Test for empty tags. HtmlTree dl = new HtmlTree(HtmlTag.DL); - html.addContent(dl); + html.add(dl); // Test for empty nested tags. HtmlTree dlTree = new HtmlTree(HtmlTag.DL); - dlTree.addContent(new HtmlTree(HtmlTag.DT)); - dlTree.addContent(new HtmlTree (HtmlTag.DD)); - html.addContent(dlTree); + dlTree.add(new HtmlTree(HtmlTag.DT)); + dlTree.add(new HtmlTree (HtmlTag.DD)); + html.add(dlTree); HtmlTree dlDisplay = new HtmlTree(HtmlTag.DL); - dlDisplay.addContent(new HtmlTree(HtmlTag.DT)); + dlDisplay.add(new HtmlTree(HtmlTag.DT)); HtmlTree dd = new HtmlTree (HtmlTag.DD); StringContent ddContent = new StringContent("Test DD"); - dd.addContent(ddContent); - dlDisplay.addContent(dd); - body.addContent(dlDisplay); + dd.add(ddContent); + dlDisplay.add(dd); + body.add(dlDisplay); StringContent emptyString = new StringContent(""); - body.addContent(emptyString); + body.add(emptyString); Comment emptyComment = new Comment(""); - body.addContent(emptyComment); + body.add(emptyComment); HtmlTree hr = new HtmlTree(HtmlTag.HR); - body.addContent(hr); - html.addContent(body); + body.add(hr); + html.add(body); HtmlDocument htmlDoc = new HtmlDocument(htmlDocType, html); return htmlDoc.toString(); } diff --git a/test/langtools/jdk/javadoc/doclet/testSerialVersionUID/TestSerialVersionUID.java b/test/langtools/jdk/javadoc/doclet/testSerialVersionUID/TestSerialVersionUID.java index 6e06fce1d82..1d22b44ebdd 100644 --- a/test/langtools/jdk/javadoc/doclet/testSerialVersionUID/TestSerialVersionUID.java +++ b/test/langtools/jdk/javadoc/doclet/testSerialVersionUID/TestSerialVersionUID.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2023, 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 @@ -42,7 +42,8 @@ public static void main(String... args) throws Exception { @Test void test() { - javadoc("-d", "out", + javadoc("-encoding", "UTF-8", + "-d", "out", testSrc("C.java")); checkExit(Exit.OK); diff --git a/test/langtools/jdk/javadoc/doclet/testTagMisuse/TestTagMisuse.java b/test/langtools/jdk/javadoc/doclet/testTagMisuse/TestTagMisuse.java index 473231e7de2..ca8a53f0980 100644 --- a/test/langtools/jdk/javadoc/doclet/testTagMisuse/TestTagMisuse.java +++ b/test/langtools/jdk/javadoc/doclet/testTagMisuse/TestTagMisuse.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2023, 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 @@ -45,7 +45,8 @@ public static void main(String... args) throws Exception { @Test void test() { - javadoc("-Xdoclint:none", + javadoc("-encoding", "UTF-8", + "-Xdoclint:none", "-d", "out", testSrc("TestTagMisuse.java")); checkExit(Exit.OK); diff --git a/test/langtools/jdk/javadoc/doclet/testThrowsHead/TestThrowsHead.java b/test/langtools/jdk/javadoc/doclet/testThrowsHead/TestThrowsHead.java index e73e6bdaa37..f3917c1c954 100644 --- a/test/langtools/jdk/javadoc/doclet/testThrowsHead/TestThrowsHead.java +++ b/test/langtools/jdk/javadoc/doclet/testThrowsHead/TestThrowsHead.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2023, 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 @@ -43,7 +43,8 @@ public static void main(String... args) throws Exception { @Test void test() { - javadoc("-d", "out", + javadoc("-encoding", "UTF-8", + "-d", "out", testSrc("C.java")); checkExit(Exit.OK); diff --git a/test/langtools/jdk/javadoc/doclet/testUnnamedPackage/TestUnnamedPackage.java b/test/langtools/jdk/javadoc/doclet/testUnnamedPackage/TestUnnamedPackage.java index b12b7f2d7f8..35dc6ce9da2 100644 --- a/test/langtools/jdk/javadoc/doclet/testUnnamedPackage/TestUnnamedPackage.java +++ b/test/langtools/jdk/javadoc/doclet/testUnnamedPackage/TestUnnamedPackage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, 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 @@ -42,7 +42,8 @@ public static void main(String... args) throws Exception { @Test void test() { - javadoc("-d", "out", + javadoc("-encoding", "UTF-8", + "-d", "out", "-sourcepath", testSrc, testSrc("C.java")); checkExit(Exit.OK); diff --git a/test/langtools/jdk/javadoc/tool/nonConstExprs/Test.java b/test/langtools/jdk/javadoc/tool/nonConstExprs/Test.java index 889945b236d..f03c928849a 100644 --- a/test/langtools/jdk/javadoc/tool/nonConstExprs/Test.java +++ b/test/langtools/jdk/javadoc/tool/nonConstExprs/Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2023, 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 @@ -34,6 +34,7 @@ public class Test { public static void main(String... args) throws Exception { File testSrc = new File(System.getProperty("test.src")); String[] jdoc_args = { + "-encoding", "UTF-8", "-d", "out", new File(testSrc, Test.class.getSimpleName() + ".java").getPath() }; diff --git a/test/langtools/tools/javac/8074306/TestSyntheticNullChecks.java b/test/langtools/tools/javac/8074306/TestSyntheticNullChecks.java index 9ba6ebf529e..ddc0a4da416 100644 --- a/test/langtools/tools/javac/8074306/TestSyntheticNullChecks.java +++ b/test/langtools/tools/javac/8074306/TestSyntheticNullChecks.java @@ -27,10 +27,10 @@ * @summary NULLCHK is emitted as Object.getClass * @compile -source 6 -target 6 TestSyntheticNullChecks.java * @run main TestSyntheticNullChecks 6 - * @clean TestSyntheticNullChecks* + * @clean * * @compile -source 7 -target 7 TestSyntheticNullChecks.java * @run main TestSyntheticNullChecks 7 - * @clean TestSyntheticNullChecks* + * @clean * * @compile TestSyntheticNullChecks.java * @run main TestSyntheticNullChecks 9 */ diff --git a/test/langtools/tools/javac/StringConcat/TestIndyStringConcat.java b/test/langtools/tools/javac/StringConcat/TestIndyStringConcat.java index 4c8917bbbf9..9910bd6d2dd 100644 --- a/test/langtools/tools/javac/StringConcat/TestIndyStringConcat.java +++ b/test/langtools/tools/javac/StringConcat/TestIndyStringConcat.java @@ -34,27 +34,27 @@ * @summary Test that StringConcat is working for JDK >= 9 * @modules jdk.jdeps/com.sun.tools.classfile * - * @clean TestIndyStringConcat* + * @clean * * @compile -source 6 -target 6 TestIndyStringConcat.java * @run main TestIndyStringConcat false * - * @clean TestIndyStringConcat* + * @clean * * @compile -source 7 -target 7 TestIndyStringConcat.java * @run main TestIndyStringConcat false * - * @clean TestIndyStringConcat* + * @clean * * @compile -source 8 -target 8 TestIndyStringConcat.java * @run main TestIndyStringConcat false * - * @clean TestIndyStringConcat* + * @clean * * @compile -XDstringConcat=inline -source 9 -target 9 TestIndyStringConcat.java * @run main TestIndyStringConcat false * - * @clean TestIndyStringConcat* + * @clean * * @compile -XDstringConcat=indy -source 9 -target 9 TestIndyStringConcat.java * @run main TestIndyStringConcat true * - * @clean TestIndyStringConcat* + * @clean * * @compile -XDstringConcat=indyWithConstants -source 9 -target 9 TestIndyStringConcat.java * @run main TestIndyStringConcat true */ diff --git a/test/lib-test/TEST.ROOT b/test/lib-test/TEST.ROOT new file mode 100644 index 00000000000..51dfcb33c4f --- /dev/null +++ b/test/lib-test/TEST.ROOT @@ -0,0 +1,9 @@ +# This file identifies the root of the test-suite hierarchy. +# It also contains test-suite configuration information. + +# Minimum jtreg version +requiredVersion=7.3.1+1 + +# Path to libraries in the topmost test directory. This is needed so @library +# does not need ../../ notation to reach them +external.lib.roots = ../../ diff --git a/test/lib-test/jdk/test/lib/hexdump/HexPrinterTest.java b/test/lib-test/jdk/test/lib/hexdump/HexPrinterTest.java new file mode 100644 index 00000000000..bad85a1e624 --- /dev/null +++ b/test/lib-test/jdk/test/lib/hexdump/HexPrinterTest.java @@ -0,0 +1,409 @@ +/* + * Copyright (c) 2019, 2020, 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. + */ + +package jdk.test.lib.hexdump; + +import jdk.test.lib.hexdump.HexPrinter; + +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; + + +/* + * @test + * @summary Check HexPrinter formatting + * @library /test/lib + * @compile HexPrinterTest.java + * @run testng jdk.test.lib.hexdump.HexPrinterTest + */ +public class HexPrinterTest { + + @Test + static void testMinimalToStringByteArray() { + int len = 16; + byte[] bytes = genData(len); + StringBuilder expected = new StringBuilder(bytes.length * 2); + for (int i = 0; i < len; i++) + expected.append(String.format("%02x", bytes[i])); + String actual = HexPrinter.minimal().toString(bytes); + System.out.println(actual); + Assert.assertEquals(actual, expected.toString(), "Minimal format incorrect"); + } + + @DataProvider(name = "ColumnParams") + Object[][] columnParams() { + return new Object[][]{ + {"%4d: ", "%d ", 10, " ; ", 50, HexPrinter.Formatters.PRINTABLE, "\n"}, + {"%03o: ", "%d ", 16, " ; ", 50, HexPrinter.Formatters.ofPrimitive(byte.class, ""), "\n"}, + {"%5d: ", "%02x:", 16, " ; ", 50, HexPrinter.Formatters.ofPrimitive(byte.class, ""), "\n"}, + {"%5d: ", "%3d", 16, " ; ", 50, HexPrinter.Formatters.ofPrimitive(byte.class, ""), "\n"}, + {"%05o: ", "%3o", 8, " ; ", 50, HexPrinter.Formatters.ofPrimitive(byte.class, ""), "\n"}, + {"%6x: ", "%02x", 8, " | ", 50, HexPrinter.Formatters.ofPrimitive(byte.class, "%d "), "\n"}, + {"%2x: ", "%02x", 8, " | ", 50, HexPrinter.Formatters.PRINTABLE, "\n"}, + {"%5d: ", "%02x", 16, " | ", 50, HexPrinter.Formatters.ofPrimitive(short.class, "%d "), "\n"}, + }; + } + + @DataProvider(name = "BuiltinParams") + Object[][] builtinParams() { + return new Object[][]{ + {"minimal", "", "%02x", 16, "", 64, HexPrinter.Formatters.NONE, ""}, + {"canonical", "%08x ", "%02x ", 16, "|", 31, HexPrinter.Formatters.ASCII, "|\n"}, + {"simple", "%5d: ", "%02x ", 16, " // ", 64, HexPrinter.Formatters.PRINTABLE, "\n"}, + {"source", " ", "(byte)%3d, ", 8, " // ", 64, HexPrinter.Formatters.PRINTABLE, + "\n"}, + }; + } + + @Test(dataProvider = "BuiltinParams") + public void testBuiltins(String name, String offsetFormat, String binFormat, int colWidth, + String annoDelim, int annoWidth, + HexPrinter.Formatter mapper, String lineSep) { + HexPrinter f = switch (name) { + case "minimal" -> HexPrinter.minimal(); + case "simple" -> HexPrinter.simple(); + case "canonical" -> HexPrinter.canonical(); + case "source" -> HexPrinter.source(); + default -> throw new IllegalStateException("Unexpected value: " + name); + }; + + testParams(f, offsetFormat, binFormat, colWidth, annoDelim, annoWidth, mapper, lineSep); + + String actual = f.toString(); + HexPrinter f2 = HexPrinter.simple() + .withOffsetFormat(offsetFormat) + .withBytesFormat(binFormat, colWidth) + .formatter(mapper, annoDelim, annoWidth) + .withLineSeparator(lineSep); + String expected = f2.toString(); + Assert.assertEquals(actual, expected, "toString of " + name + " does not match"); + } + + @Test(dataProvider = "ColumnParams") + public void testToStringTwoLines(String offsetFormat, String binFormat, int colWidth, + String annoDelim, int annoWidth, + HexPrinter.Formatter mapper, String lineSep) { + HexPrinter f = HexPrinter.simple() + .withOffsetFormat(offsetFormat) + .withBytesFormat(binFormat, colWidth) + .formatter(mapper, annoDelim, annoWidth) + .withLineSeparator(lineSep); + testParams(f, offsetFormat, binFormat, colWidth, annoDelim, annoWidth, mapper, lineSep); + } + + public static void testParams(HexPrinter printer, String offsetFormat, String binFormat, int colWidth, + String annoDelim, int annoWidth, + HexPrinter.Formatter mapper, String lineSep) { + byte[] bytes = genData(colWidth * 2); + System.out.println("Params: " + printer.toString()); + String out = printer.toString(bytes); + System.out.println(out); + + // Compare the actual output with the expected output of each formatting element + int padToWidth = colWidth * String.format(binFormat, 0xff).length(); + int ndx = 0; + int valuesStart = 0; + int l; + for (int i = 0; i < bytes.length; i++) { + if (i % colWidth == 0) { + String offset = String.format(offsetFormat, i); + l = offset.length(); + Assert.assertEquals(out.substring(ndx, ndx + l), offset, + "offset format mismatch: " + ndx); + ndx += l; + valuesStart = ndx; + } + String value = String.format(binFormat, (0xff & bytes[i])); + l = value.length(); + Assert.assertEquals(out.substring(ndx, ndx + l), value, + "value format mismatch: " + ndx + ", i: " + i); + ndx += l; + if (((i + 1) % colWidth) == 0) { + // Rest of line is for padding, delimiter, formatter + String padding = " ".repeat(padToWidth - (ndx - valuesStart)); + Assert.assertEquals(out.substring(ndx, ndx + padding.length()), padding, "padding"); + ndx += padding.length(); + Assert.assertEquals(out.substring(ndx, ndx + annoDelim.length()), annoDelim, + "delimiter mismatch"); + ndx += annoDelim.length(); + + // Formatter output is tested separately + ndx = out.indexOf(lineSep, ndx) + lineSep.length(); + } + } + } + + @DataProvider(name = "PrimitiveFormatters") + Object[][] formatterParams() { + return new Object[][]{ + {byte.class, ""}, + {byte.class, "%02x: "}, + {short.class, "%d "}, + {int.class, "%08x, "}, + {long.class, "%16x "}, + {float.class, "%3.4f "}, + {double.class, "%6.3g "}, + {boolean.class, "%b "}, + }; + } + + @Test(dataProvider = "PrimitiveFormatters") + public void testFormatter(Class primClass, String fmtString) { + HexPrinter.Formatter formatter = HexPrinter.Formatters.ofPrimitive(primClass, fmtString); + // Create a byte array with data for two lines + int colWidth = 8; + byte[] bytes = genData(colWidth); + StringBuilder sb = new StringBuilder(); + DataInputStream in = new DataInputStream(new ByteArrayInputStream(bytes)); + DataInputStream in2 = new DataInputStream(new ByteArrayInputStream(bytes)); + try { + while (true) { + formatter.annotate(in, sb); + Object n = readPrimitive(primClass, in2); + String expected = String.format(fmtString, n); + Assert.assertEquals(sb.toString(), expected, "mismatch"); + sb.setLength(0); + } + } catch (IOException ioe) { + // EOF is done + } + try { + Assert.assertEquals(in.available(), 0, "not all input consumed"); + Assert.assertEquals(in2.available(), 0, "not all 2nd stream input consumed"); + } catch (IOException ioe) { + // + } + } + + @Test(dataProvider = "PrimitiveFormatters") + static void testHexPrinterPrimFormatter(Class primClass, String fmtString) { + // Create a byte array with data for two lines + int colWidth = 8; + byte[] bytes = genData(colWidth); + + HexPrinter p = HexPrinter.simple() + .formatter(primClass, fmtString); + String actual = p.toString(bytes); + System.out.println(actual); + // The formatter should produce the same output as using the formatter method + // with an explicit formatter for the primitive + String expected = HexPrinter.simple() + .formatter(HexPrinter.Formatters.ofPrimitive(primClass, fmtString)) + .toString(bytes); + Assert.assertEquals(actual, expected, "mismatch"); + } + + private static Object readPrimitive(Class primClass, DataInputStream in) throws IOException { + if (int.class.equals(primClass)) { + return in.readInt(); + } else if (byte.class.equals(primClass)) { + return (int) in.readByte(); + } else if (short.class.equals(primClass)) { + return in.readShort(); + } else if (char.class.equals(primClass)) { + return in.readChar(); + } else if (long.class.equals(primClass)) { + return in.readLong(); + } else if (float.class.equals(primClass)) { + return in.readFloat(); + } else if (double.class.equals(primClass)) { + return in.readDouble(); + } else if (boolean.class.equals(primClass)) { + return in.readBoolean(); + } else { + throw new RuntimeException("unknown primitive class: " + primClass); + } + } + + @DataProvider(name = "sources") + Object[][] sources() { + return new Object[][]{ + {genBytes(21), 0, -1}, + {genBytes(21), 5, 12}, + }; + } + + public static byte[] genData(int len) { + // Create a byte array with data for two lines + byte[] bytes = new byte[len]; + for (int i = 0; i < len / 2; i++) { + bytes[i] = (byte) (i + 'A'); + bytes[i + len / 2] = (byte) (i + 'A' + 128); + } + return bytes; + } + + public static byte[] genFloat(int len) { + byte[] bytes = null; + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(baos)) { + for (int i = 0; i < len; i++) { + out.writeFloat(i); + } + bytes = baos.toByteArray(); + } catch (IOException unused) { + } + return bytes; + } + + public static byte[] genDouble(int len) { + byte[] bytes = null; + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(baos)) { + for (int i = 0; i < len; i++) { + out.writeDouble(i); + } + bytes = baos.toByteArray(); + } catch (IOException unused) { + } + return bytes; + } + + public static byte[] genBytes(int len) { + byte[] bytes = new byte[len]; + for (int i = 0; i < len; i++) + bytes[i] = (byte) ('A' + i); + return bytes; + } + + public ByteBuffer genByteBuffer(int len) { + return ByteBuffer.wrap(genBytes(len)); + } + + public InputStream genInputStream(int len) { + return new ByteArrayInputStream(genBytes(len)); + } + + @Test + public void testNilPrinterBigBuffer() { + byte[] bytes = new byte[1024]; + HexPrinter p = HexPrinter.minimal(); + String r = p.toString(bytes); + Assert.assertEquals(r.length(), bytes.length * 2, "encoded byte wrong size"); + Assert.assertEquals(r.replace("00", "").length(), 0, "contents not all zeros"); + } + + @Test(dataProvider = "sources") + public void testToStringByteBuffer(byte[] bytes, int offset, int length) { + if (length < 0) + length = bytes.length - offset; + ByteBuffer bb = ByteBuffer.wrap(bytes, 0, bytes.length); + System.out.printf("Source: %s, off: %d, len: %d%n", + bytes.getClass().getName(), offset, length); + String actual; + if (offset == 0 && length < 0) { + bb.position(offset); + bb.limit(length); + actual = HexPrinter.simple().toString(bb); + } else + actual = HexPrinter.simple().toString(bb, offset, length); + System.out.println(actual); + String expected = HexPrinter.simple().toString(bytes, offset, length); + Assert.assertEquals(actual, expected, "mismatch in format()"); + } + + @Test(dataProvider = "sources") + public void testFormatBytes(byte[] bytes, int offset, int length) { + int len = length >= 0 ? length : bytes.length; + System.out.printf("Source: %s, off: %d, len: %d%n", + "bytes", offset, len); + StringBuilder sb = new StringBuilder(); + if (offset == 0 && length < 0) + HexPrinter.simple().dest(sb).format(bytes); + else + HexPrinter.simple().dest(sb).format(bytes, offset, len); + String actual = sb.toString(); + System.out.println(actual); + String expected = HexPrinter.simple().toString(bytes, offset, len); + Assert.assertEquals(actual, expected, "mismatch in format()"); + } + + @Test(dataProvider = "sources") + public void testFormatByteBuffer(byte[] bytes, int offset, int length) { + if (length < 0) + length = bytes.length - offset; + ByteBuffer bb = ByteBuffer.wrap(bytes, 0, bytes.length); + System.out.printf("Source: %s, off: %d, len: %d%n", + bytes.getClass().getName(), offset, length); + StringBuilder sb = new StringBuilder(); + if (offset == 0 && length < 0) { + bb.position(offset); + bb.limit(length); + HexPrinter.simple().dest(sb).format(bb); + } else + HexPrinter.simple().dest(sb).format(bb, offset, length); + String actual = sb.toString(); + System.out.println(actual); + String expected = HexPrinter.simple().toString(bytes, offset, length); + Assert.assertEquals(actual, expected, "mismatch in format()"); + } + + @Test(dataProvider = "sources") + public void testFormatInputStream(byte[] bytes, int offset, int length) { + // Offset is ignored + InputStream is = new ByteArrayInputStream(bytes, 0, length); + StringBuilder sb = new StringBuilder(); + System.out.printf("Source: %s, off: %d, len: %d%n", + bytes.getClass().getName(), offset, length); + HexPrinter.simple().dest(sb).format(is); + String actual = sb.toString(); + System.out.println(actual); + String expected = HexPrinter.simple().toString(bytes, 0, length); + Assert.assertEquals(actual, expected, "mismatch in format()"); + } + + @Test(expectedExceptions = NullPointerException.class) + public void testNullByteArray() { + HexPrinter.simple().dest(System.out).format((byte[]) null); + } + + @Test(expectedExceptions = NullPointerException.class) + public void testNullByteArrayOff() { + HexPrinter.simple().dest(System.out).format((byte[]) null, 0, 1); + } + + @Test(expectedExceptions = NullPointerException.class) + public void testNullByteBuffer() { + HexPrinter.simple().dest(System.out).format((ByteBuffer) null); + } + + @Test(expectedExceptions = NullPointerException.class) + public void testNullByteBufferOff() { + HexPrinter.simple().dest(System.out).format((ByteBuffer) null, 0, 1); + } + + @Test(expectedExceptions = NullPointerException.class) + public void testNullInputStream() { + HexPrinter.simple().dest(System.out).format((InputStream) null); + } + +} diff --git a/test/lib/jdk/test/lib/Platform.java b/test/lib/jdk/test/lib/Platform.java index b310873d1b6..e1511772e70 100644 --- a/test/lib/jdk/test/lib/Platform.java +++ b/test/lib/jdk/test/lib/Platform.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2023, 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 @@ -23,14 +23,17 @@ package jdk.test.lib; +import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.IOException; +import java.io.InputStreamReader; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; import java.util.regex.Pattern; public class Platform { @@ -257,57 +260,81 @@ public static boolean hasSA() { return true; } - /** - * Return true if the test JDK is signed, otherwise false. Only valid on OSX. - */ - public static boolean isSignedOSX() throws IOException { - // We only care about signed binaries for 10.14 and later (actually 10.14.5, but - // for simplicity we'll also include earlier 10.14 versions). - if (getOsVersionMajor() == 10 && getOsVersionMinor() < 14) { - return false; // assume not signed - } - - // Find the path to the java binary. + private static Process launchCodesignOnJavaBinary() throws IOException { String jdkPath = System.getProperty("java.home"); Path javaPath = Paths.get(jdkPath + "/bin/java"); String javaFileName = javaPath.toAbsolutePath().toString(); if (!javaPath.toFile().exists()) { throw new FileNotFoundException("Could not find file " + javaFileName); } - - // Run codesign on the java binary. - ProcessBuilder pb = new ProcessBuilder("codesign", "-d", "-v", javaFileName); - pb.redirectError(ProcessBuilder.Redirect.DISCARD); - pb.redirectOutput(ProcessBuilder.Redirect.DISCARD); + ProcessBuilder pb = new ProcessBuilder("codesign", "--display", "--verbose", javaFileName); + pb.redirectErrorStream(true); // redirect stderr to stdout Process codesignProcess = pb.start(); + return codesignProcess; + } + + public static boolean hasOSXPlistEntries() throws IOException { + Process codesignProcess = launchCodesignOnJavaBinary(); + BufferedReader is = new BufferedReader(new InputStreamReader(codesignProcess.getInputStream())); + String line; + while ((line = is.readLine()) != null) { + System.out.println("STDOUT: " + line); + if (line.indexOf("Info.plist=not bound") != -1) { + return false; + } + if (line.indexOf("Info.plist entries=") != -1) { + return true; + } + } + System.out.println("No matching Info.plist entry was found"); + return false; + } + + /** + * Return true if the test JDK is hardened, otherwise false. Only valid on OSX. + */ + public static boolean isHardenedOSX() throws IOException { + // We only care about hardened binaries for 10.14 and later (actually 10.14.5, but + // for simplicity we'll also include earlier 10.14 versions). + if (getOsVersionMajor() == 10 && getOsVersionMinor() < 14) { + return false; // assume not hardened + } + Process codesignProcess = launchCodesignOnJavaBinary(); + BufferedReader is = new BufferedReader(new InputStreamReader(codesignProcess.getInputStream())); + String line; + boolean isHardened = false; + boolean hardenedStatusConfirmed = false; // set true when we confirm whether or not hardened + while ((line = is.readLine()) != null) { + System.out.println("STDOUT: " + line); + if (line.indexOf("flags=0x10000(runtime)") != -1 ) { + hardenedStatusConfirmed = true; + isHardened = true; + System.out.println("Target JDK is hardened. Some tests may be skipped."); + } else if (line.indexOf("flags=0x20002(adhoc,linker-signed)") != -1 ) { + hardenedStatusConfirmed = true; + isHardened = false; + System.out.println("Target JDK is adhoc signed, but not hardened."); + } else if (line.indexOf("code object is not signed at all") != -1) { + hardenedStatusConfirmed = true; + isHardened = false; + System.out.println("Target JDK is not signed, therefore not hardened."); + } + } + if (!hardenedStatusConfirmed) { + System.out.println("Could not confirm if TargetJDK is hardened. Assuming not hardened."); + isHardened = false; + } + try { if (codesignProcess.waitFor(10, TimeUnit.SECONDS) == false) { - System.err.println("Timed out waiting for the codesign process to complete. Assuming not signed."); + System.err.println("Timed out waiting for the codesign process to complete. Assuming not hardened."); codesignProcess.destroyForcibly(); - return false; // assume not signed + return false; // assume not hardened } } catch (InterruptedException e) { throw new RuntimeException(e); } - - // Check codesign result to see if java binary is signed. Here are the - // exit code meanings: - // 0: signed - // 1: not signed - // 2: invalid arguments - // 3: only has meaning with the -R argument. - // So we should always get 0 or 1 as an exit value. - if (codesignProcess.exitValue() == 0) { - System.out.println("Target JDK is signed. Some tests may be skipped."); - return true; // signed - } else if (codesignProcess.exitValue() == 1) { - System.out.println("Target JDK is not signed."); - return false; // not signed - } else { - System.err.println("Executing codesign failed. Assuming unsigned: " + - codesignProcess.exitValue()); - return false; // not signed - } + return isHardened; } private static boolean isArch(String archnameRE) { @@ -316,6 +343,20 @@ private static boolean isArch(String archnameRE) { .matches(); } + public static boolean isOracleLinux7() { + if (System.getProperty("os.name").toLowerCase().contains("linux") && + System.getProperty("os.version").toLowerCase().contains("el")) { + Pattern p = Pattern.compile("el(\\d+)"); + Matcher m = p.matcher(System.getProperty("os.version")); + if (m.find()) { + try { + return Integer.parseInt(m.group(1)) <= 7; + } catch (NumberFormatException nfe) {} + } + } + return false; + } + /** * Returns file extension of shared library, e.g. "so" on linux, "dll" on windows. * @return file extension diff --git a/test/lib/jdk/test/lib/SA/SATestUtils.java b/test/lib/jdk/test/lib/SA/SATestUtils.java index 36480c690b9..d578c2ee57c 100644 --- a/test/lib/jdk/test/lib/SA/SATestUtils.java +++ b/test/lib/jdk/test/lib/SA/SATestUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, 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 @@ -30,12 +30,12 @@ import java.security.PrivilegedExceptionAction; import java.util.ArrayList; import java.util.Arrays; -import java.util.List; import java.util.concurrent.TimeUnit; import jdk.test.lib.JDKToolLauncher; import jdk.test.lib.Platform; import jtreg.SkippedException; +import java.util.List; public class SATestUtils { /** @@ -63,8 +63,8 @@ public static void skipIfCannotAttach() { throw new SkippedException("SA Attach not expected to work. Ptrace attach not supported."); } } else if (Platform.isOSX()) { - if (Platform.isSignedOSX()) { - throw new SkippedException("SA Attach not expected to work. JDK is signed."); + if (Platform.isHardenedOSX()) { + throw new SkippedException("SA Attach not expected to work. JDK is hardened."); } if (!Platform.isRoot() && !canAddPrivileges()) { throw new SkippedException("SA Attach not expected to work. Insufficient privileges (not root and can't use sudo)."); diff --git a/test/lib/jdk/test/lib/apps/LingeredApp.java b/test/lib/jdk/test/lib/apps/LingeredApp.java index e454a96bbdd..147870b1fce 100644 --- a/test/lib/jdk/test/lib/apps/LingeredApp.java +++ b/test/lib/jdk/test/lib/apps/LingeredApp.java @@ -44,6 +44,7 @@ import jdk.test.lib.Utils; import jdk.test.lib.process.OutputBuffer; import jdk.test.lib.process.StreamPumper; +import jdk.test.lib.util.CoreUtils; /** * This is a framework to launch an app that could be synchronized with caller @@ -85,6 +86,8 @@ public class LingeredApp { protected static final int appWaitTime = 100; protected final String lockFileName; + protected boolean forceCrash = false; // set true to force a crash and core file + /** * Create LingeredApp object on caller side. Lock file have be a valid filename * at writable location @@ -100,6 +103,12 @@ public LingeredApp() { this.lockFileName = lockName; } + public void setForceCrash(boolean forceCrash) { + this.forceCrash = forceCrash; + } + + native private static int crash(); + /** * * @return name of lock file @@ -273,7 +282,11 @@ public void waitAppReady(long timeout) throws IOException { // Make sure process didn't already exit if (!appProcess.isAlive()) { - throw new IOException("App exited unexpectedly with " + appProcess.exitValue()); + if (forceCrash) { + return; // This is expected. Just return. + } else { + throw new IOException("App exited unexpectedly with " + appProcess.exitValue()); + } } try { @@ -321,6 +334,11 @@ public List runAppPrepare(List vmArguments) { // Lets user manage LingeredApp options cmd.addAll(vmArguments); } + if (forceCrash) { + cmd.add("-XX:+CreateCoredumpOnCrash"); + // We need to find libLingeredApp.so for the crash() native method + cmd.add("-Djava.library.path=" + System.getProperty("java.library.path")); + } // Make sure we set correct classpath to run the app cmd.add("-cp"); @@ -356,10 +374,17 @@ public void runApp(List vmArguments) cmd.add(this.getAppName()); cmd.add(lockFileName); + if (forceCrash) { + cmd.add("forceCrash"); // Let the subprocess know to force a crash + } printCommandLine(cmd); ProcessBuilder pb = new ProcessBuilder(cmd); + if (forceCrash) { + // If we are going to force a core dump, apply "ulimit -c unlimited" if we can. + pb = CoreUtils.addCoreUlimitCommand(pb); + } // ProcessBuilder.start can throw IOException appProcess = pb.start(); @@ -493,19 +518,37 @@ public static boolean isLastModifiedWorking() { } /** - * This part is the application it self + * This part is the application itself. First arg is optional "forceCrash". + * Following arg is the lock file name. */ public static void main(String args[]) { + boolean forceCrash = false; - if (args.length != 1) { + if (args.length == 0) { System.err.println("Lock file name is not specified"); System.exit(7); + } else if (args.length > 2) { + System.err.println("Too many arguments specified: " + args.length); + System.exit(7); + } + + if (args.length == 2) { + if (args[1].equals("forceCrash")) { + forceCrash = true; + } else { + System.err.println("Invalid 1st argment: " + args[1]); + System.exit(7); + } } String theLockFileName = args[0]; Path path = Paths.get(theLockFileName); try { + if (forceCrash) { + System.loadLibrary("LingeredApp"); // location of native crash() method + crash(); + } while (Files.exists(path)) { // Touch the lock to indicate our readiness setLastModified(theLockFileName, epoch()); diff --git a/test/lib/jdk/test/lib/apps/libLingeredApp.c b/test/lib/jdk/test/lib/apps/libLingeredApp.c new file mode 100644 index 00000000000..d02c3e7b8bb --- /dev/null +++ b/test/lib/jdk/test/lib/apps/libLingeredApp.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2020, 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. + */ + +#include + +// Borrowed from hotspot vmError.cpp. +// Returns an address which is guaranteed to generate a SIGSEGV on read, +// which is not NULL and contains bits in every word +void* get_segfault_address() { + return (void*) +#ifdef _LP64 + 0xABC0000000000ABCULL; +#else + 0x00000ABC; +#endif +} + +JNIEXPORT jint JNICALL +Java_jdk_test_lib_apps_LingeredApp_crash(JNIEnv *env, jclass clss) +{ + return *(jint *)get_segfault_address(); +} diff --git a/test/lib/jdk/test/lib/hexdump/HexPrinter.java b/test/lib/jdk/test/lib/hexdump/HexPrinter.java new file mode 100644 index 00000000000..ad4575d14e9 --- /dev/null +++ b/test/lib/jdk/test/lib/hexdump/HexPrinter.java @@ -0,0 +1,1181 @@ +/* + * Copyright (c) 2019, 2020, 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. + */ + +package jdk.test.lib.hexdump; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.CharArrayWriter; +import java.io.DataInputStream; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintStream; +import java.io.UncheckedIOException; +import java.io.Writer; +import java.nio.ByteBuffer; +import java.util.Objects; + +/** + * Decode a sequence of bytes to a readable format. + *

+ * The predefined formats are: + *

+ *
{@link #minimal() Minimal format}: {@code "Now is the time for Java.\n"}
+ *
    {@code
+ *     4e6f77206973207468652074696d6520666f72204a6176612e0a} 
+ *
+ * + *
{@link #simple() Simple format}: {@code "Now is the time for Java.\n"}
+ *
{@code
+ *     0: 4e 6f 77 20 69 73 20 74 68 65 20 74 69 6d 65 20  // Now is the time for Java.\n
+ *    16: 66 6f 72 20 4a 61 76 61 2e 0a} 
+ *
+ * + *
{@link #canonical() Canonical format}: {@code "Now is the time for Java.\n"}
+ *
{@code
+ *     00000000  4e 6f 77 20 69 73 20 74 68 65 20 74 69 6d 65 20 |Now is the time |
+ *     00000010  66 6f 72 20 4a 61 76 61 2e 0a                   |for Java.|} 
+ *
+ *
{@link #source() Byte array initialization source}: {@code "Now is the time for Java.\n"}
+ *
{@code
+ *     (byte) 78, (byte)111, (byte)119, (byte) 32, (byte)105, (byte)115, (byte) 32, (byte)116,  // Now is t
+ *     (byte)104, (byte)101, (byte) 32, (byte)116, (byte)105, (byte)109, (byte)101, (byte) 32,  // he time
+ *     (byte)102, (byte)111, (byte)114, (byte) 32, (byte) 74, (byte) 97, (byte)118, (byte) 97,  // for Java
+ *     (byte) 46, (byte) 10,                                                                    // .\n}
+ *
+ *
+ *

+ * The static factories {@link #minimal minimal}, {@link #simple simple}, + * {@link #canonical canonical}, and {@link #source() Java source} + * return predefined {@code HexPrinter}s for the formats above. + * HexPrinter holds the formatting parameters that control the width and formatting + * of each of the offset, byte values, and formatted output. + * New HexPrinters with different parameters are created using an existing HexPrinter + * as a template with the methods {@link #formatter(Formatter)}, + * {@link #withBytesFormat(String, int)}, {@link #withOffsetFormat(String)}, + * and {@link #withLineSeparator(String)}. + *

+ * The source of the bytes includes byte arrays, InputStreams, and ByteBuffers. + * For example, {@link #toString(InputStream)} reads the input and returns a String. + * Each of the {@code toString(...)} methods immediately reads and + * formats all of the bytes from the source and returns a String. + *

+ * Each of the {@code format(...)} methods immediately reads and + * formats all of the bytes from the source and appends it to the destination. + * For example, {@link #format(InputStream)} reads the input and + * appends the output to {@link System#out System.out} unless the + * {@link #dest(Appendable) destination} is changed to an {@link Appendable} + * such as {@link PrintStream}, {@link StringBuilder}, or {@link Writer}. + *

+ * {@linkplain Formatter Formatter} functions read and interpret the bytes to show the + * structure and content of a protocol or data stream. + * Built-in formatters include {@link HexPrinter#formatter(Class, String) primitives}, + * {@link Formatters#PRINTABLE printable ascii}, + * and {@link Formatters#utf8Parser(DataInputStream, Appendable) UTF-8 strings}. + * The {@link #formatter(Formatter, String, int) formatter} method sets the + * formatting function, the delimiter, and the width. + * Custom formatter functions can be implemented as a lambda, a method, an inner class, or a concrete class. + *

+ * The format of each line is customizable. + * The {@link #withOffsetFormat(String) withOffsetFormat} method controls + * the format of the byte offset. + * The {@link #withBytesFormat(String, int) withBytesFormat} method controls + * the printing of each byte value including the separator, + * and the maximum number of byte values per line. + * The offset and byte values are formatted using the familiar + * {@link String#format String formats} with spacing + * and delimiters included in the format string. + * The {@link #withLineSeparator(String) withLineSeparator} method sets + * the line separator. + *

+ * Examples: + *

    + *
  • Encoding bytes to a minimal string. + *
    {@code
    + * byte[] bytes = new byte[] { ' ', 0x41, 0x42, '\n'};
    + * String s = HexPrinter.minimal().toString(bytes);
    + * Result: "2041420a"
    + * }
    + *
  • Simple formatting of a byte array. + *
    {@code
    + * byte[] bytes = new byte[] { ' ', 0x41, 0x42, '\n'};
    + * String s = HexPrinter.simple().toString(bytes);
    + * Result:    0: 20 41 42 0a                                      //  AB\n
    + * }
    + *
  • Simple formatting of a ByteBuffer. + *
    {@code
    + * ByteBuffer bb = ByteBuffer.wrap(bytes);
    + * String s = HexPrinter.simple().toString(bb);
    + * Result:    0: 20 41 42 0a                                      //  AB\n
    + * }
    + *
  • Simple formatting of ranges of a byte array to System.err. + *
    {@code
    + * byte[] bytes = new byte[] { ' ', 0x41, 0x42, 0x43, 0x44, '\n'};
    + * HexPrinter hex = HexPrinter.simple()
    + *                            .dest(System.err);
    + *                            .format(bytes, 1, 2)
    + *                            .format(bytes, 3, 2);
    + * Result:
    + * 1: 41 42                                            // AB
    + * 3: 43 44                                            // CD
    + * }
    + *
+ *

+ * This is a value-based + * class; use of identity-sensitive operations (including reference equality + * ({@code ==}), identity hash code, or synchronization) on instances + * may have unpredictable results and should be avoided. + * The {@code equals} method should be used for comparisons. + * + *

+ * This class is immutable and thread-safe. + */ +public final class HexPrinter { + + /** + * Mnemonics for control characters. + */ + static final String[] CONTROL_MNEMONICS = { + "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel", + "b", "t", "n", "vt", "f", "r", "so", "si", + "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb", + "can", "em", "sub", "esc", "fs", "gs", "rs", "us" + }; + private static final String initOffsetFormat = "%5d: "; + private static final int initBytesCount = 16; // 16 byte values + private static final String initBytesFormat = "%02x "; + private static final int initAnnoWidth = initBytesCount * 4; + private static final String initAnnoDelim = " // "; + + final Appendable dest; // Final output target + final String offsetFormat; // Byte offset Formatter String + final String bytesFormat; // Hex bytes Formatter string + final int bytesCount; // Maximum number of byte values per line + final String annoDelim; // Annotation delimiter + final int annoWidth; // Annotation field width (characters) + final String lineSeparator; // End of line separator + final Formatter annoFormatter; // formatter function + + /** + * Construct a new HexPrinter with all new values. + * + * @param printer the formatter + * @param offsetFormat the offset format + * @param bytesFormat the bytes format + * @param bytesCount the count of bytes per line + * @param annoDelim the delimiter before the annotation + * @param annoWidth the width of the annotation + * @param lineSeparator the line separator + * @param dest the destination + */ + private HexPrinter(Formatter printer, String offsetFormat, String bytesFormat, int bytesCount, + String annoDelim, int annoWidth, + String lineSeparator, Appendable dest) { + this.annoFormatter = Objects.requireNonNull(printer, "formatter"); + this.bytesCount = bytesCount; + this.bytesFormat = Objects.requireNonNull(bytesFormat, bytesFormat); + this.offsetFormat = Objects.requireNonNull(offsetFormat, "offsetFormat"); + this.annoDelim = Objects.requireNonNull(annoDelim, "annoDelim"); + this.annoWidth = annoWidth; + this.lineSeparator = Objects.requireNonNull(lineSeparator, "lineSeparator"); + this.dest = Objects.requireNonNull(dest, "dest"); + } + + /** + * Returns a new HexPrinter setting the parameters to produce a minimal string. + * The parameters are set to: + *

    + *
  • byte offset format: none {@code ""}, + *
  • each byte value is formatted as 2 hex digits: {@code "%02x"}, + *
  • maximum number of byte values per line: unbounded, + *
  • delimiter for the annotation: none {@code ""}, + *
  • formatter: {@link Formatters#NONE does not output a formatted byte}, and + *
  • destination: {@link System#out System.out}. + *
+ * Example, + *
+     * {@code     byte[] bytes = new byte[] { ' ', 0x41, 0x42, '\n'};
+     *     String s = HexPrinter.minimal()
+     *             .toString(bytes);
+     *     Result: "2041420a"
+     * }
+ * + * @return a new HexPrinter + */ + public static HexPrinter minimal() { + return new HexPrinter(Formatters.NONE, "", + "%02x", initBytesCount, + "", initAnnoWidth, "", + System.out); + } + + /** + * Returns a new HexPrinter setting the parameters to produce canonical output. + * The parameters are set to: + *
    + *
  • byte offset format: {@code "%08x "}, + *
  • each byte value is formatted as 2 hex digits and a space: {@code "%02x "}, + *
  • maximum number of byte values per line: {@value initBytesCount}, + *
  • delimiter for the annotation: {@code "|"}, + *
  • formatter: {@link Formatters#ASCII ASCII bytes}, and + *
  • line separator: "|" + {@link System#lineSeparator()}, + *
  • destination: {@link System#out System.out}. + *
+ * Example, + *
+     * {@code     byte[] bytes = new byte[] { ' ', 0x41, 0x42, '\n'};
+     *     String s = HexPrinter.canonical()
+     *             .toString(bytes);
+     *
+     *     Result: "00000000  20 41 42 0a                                     | AB|"
+     * }
+ * + * @return a new HexPrinter + */ + public static HexPrinter canonical() { + return new HexPrinter(Formatters.ASCII, "%08x ", + "%02x ", initBytesCount, + "|", 31, "|" + System.lineSeparator(), + System.out); + } + + /** + * Returns a new HexPrinter setting simple formatting parameters to output + * to a multi-line string. + * The parameters are set to: + *
    + *
  • byte offset format: signed decimal width 5 and a space, {@code "%5d: "}, + *
  • each byte value is formatted as 2 hex digits and a space: {@code "%02x "}, + *
  • maximum number of byte values per line: {@value initBytesCount}, + *
  • delimiter for the annotation: {@code " // "}, + *
  • width for the annotation: {@value initAnnoWidth}, + *
  • line separator: {@link System#lineSeparator()}, + *
  • formatter: {@link Formatters#PRINTABLE printable ASCII} + * showing printable characters, mnemonics for control chars, and + * otherwise the decimal byte values, + *
  • destination default: {@link System#out System.out}. + *
+ * Example, + *
+     * {@code    byte[] bytes = new byte[] { ' ', 0x41, 0x42, '\n'};
+     *    String s = HexPrinter.simple()
+     *            .toString(bytes);
+     *
+     *    Result: "    0: 20 41 42 0a                                      //  AB\n"
+     * }
+ * + * @return a new HexPrinter + */ + public static HexPrinter simple() { + return new HexPrinter(Formatters.PRINTABLE, initOffsetFormat, + initBytesFormat, initBytesCount, + initAnnoDelim, initAnnoWidth, System.lineSeparator(), + System.out); + } + + /** + * Returns a new HexPrinter setting formatting parameters to output + * to a multi-line string as a byte array initialization for Java source. + * The parameters are set to: + *
    + *
  • byte offset format: 4 space indent: {@code " "}, + *
  • each byte value is formatted as: {@code "(byte)%3d, "}, + *
  • maximum number of byte values per line: {@code 8}, + *
  • delimiter for the annotation: {@code " // "}, + *
  • width for the annotation: {@value initAnnoWidth}, + *
  • line separator: {@link System#lineSeparator()}, + *
  • formatter: {@link Formatters#PRINTABLE printable ASCII} + * showing printable characters, mnemonics for control chars, and + * otherwise the decimal byte values, + *
  • destination default: {@link System#out System.out}. + *
+ * + * @return a new HexPrinter + */ + public static HexPrinter source() { + return new HexPrinter(Formatters.PRINTABLE, " ", + "(byte)%3d, ", 8, + " // ", initAnnoWidth, System.lineSeparator(), + System.out); + } + + /** + * Returns a new HexPrinter setting the destination to the Appendable. + * {@code Appendable} classes include: {@link PrintStream}, {@link Writer}, + * {@link StringBuilder}, and {@link StringBuffer}. + * + * @param dest the Appendable destination for the output, non-null + * @return a new HexPrinter + * @throws UncheckedIOException if an I/O error occurs + */ + public HexPrinter dest(Appendable dest) { + Objects.requireNonNull(dest, "dest"); + return new HexPrinter(annoFormatter, offsetFormat, + bytesFormat, bytesCount, annoDelim, + annoWidth, lineSeparator, dest); + } + + /** + * The formatter function is called repeatedly to read all of the bytes + * and append the output. + * All output is appended and flushed to the destination. + *

+ * The result is equivalent to calling + * {@code format(new ByteArrayInputStream(source))}. + * + * @param source a non-null array of bytes. + * @return this HexPrinter + * @throws java.io.UncheckedIOException if an I/O error occurs + */ + public HexPrinter format(byte[] source) { + Objects.requireNonNull(source, "byte array must be non-null"); + return format(new ByteArrayInputStream(source)); + } + + /** + * The formatter function is called repeatedly to read the bytes from offset + * for length and append the output. + * All output is appended and flushed to the destination. + * Only {@code length} bytes starting at the {@code offset} are formatted. + *

+ * The result is equivalent to calling + * {@code format(new ByteArrayInputStream(source, offset, len))}. + * + * @param source a non-null array of bytes. + * @param offset the offset into the array to start + * @param length the length of bytes in the array to format + * @return this HexPrinter + * @throws java.io.UncheckedIOException if an I/O error occurs + */ + public HexPrinter format(byte[] source, int offset, int length) { + Objects.requireNonNull(source, "byte array must be non-null"); + return format(new ByteArrayInputStream(source, offset, length), offset); + } + + /** + * The formatter function is called repeatedly to read all of the bytes + * and append the output. + * All output is appended and flushed to the destination. + *

+ * The {@code format} method invokes the {@code formatter} to read bytes from the + * source and append the formatted sequence of byte values to the destination. + * As the bytes are read they are printed using the {@link #withBytesFormat} + * to fill the bytes values of the output destination. + * The output of the {@code formatter} fills the annotation field. + * A new line is started when either the byte values or annotation + * is filled to its respective width. The offset of the first byte on the line + * is inserted at the beginning of each line using {@link #withOffsetFormat(String)}. + *

+ * This method may block indefinitely reading from the input stream, + * or writing to the output stream. The behavior for the case where + * the input and/or output stream is asynchronously closed, + * or the thread interrupted during the transfer, is highly input + * and output stream specific, and therefore not specified. + *

+ * If an I/O error occurs reading from the input stream or + * writing to the output stream, then it may do so after some bytes + * have been read or written. Consequently the input stream + * may not be at end of stream and one, or both, streams may be + * in an inconsistent state. It is strongly recommended that both streams + * be promptly closed if an I/O error occurs. + * + * @param source an InputStream to read from, the stream not closed and + * is at end-of-file. + * @return this HexPrinter + * @throws java.io.UncheckedIOException if an I/O error occurs + */ + public HexPrinter format(InputStream source) { + return format(source, 0); + } + + /** + * Format an InputStream and supply the initial offset. + * + * @param source an InputStream + * @param offset an offset + * @return this HexPrinter + */ + private HexPrinter format(InputStream source, int offset) { + Objects.requireNonNull(source, "InputStream must be non-null"); + try (AnnotationWriter writer = + new AnnotationWriter(this, source, offset, dest)) { + writer.flush(); + return this; + } + } + + /** + * The formatter function is called repeatedly to read the bytes + * from the offset for the length and append the output. + * All annotation output is appended and flushed to the output destination. + * The ByteBuffer position and limit are unused and not modified. + * + * @param source a ByteBuffer + * @param offset the offset in the ByteBuffer + * @param length the length in the ByteBuffer + * @return this HexPrinter + * @throws java.io.UncheckedIOException if an I/O error occurs + */ + public HexPrinter format(ByteBuffer source, int offset, int length) { + Objects.requireNonNull(source, "ByteBuffer must be non-null"); + ByteArrayInputStream bais; + if (source.hasArray() && !source.isReadOnly()) { + bais = new ByteArrayInputStream(source.array(), offset, length); + } else { + int size = source.limit() - source.position(); + byte[] bytes = new byte[size]; + source.get(bytes, offset, length); + bais = new ByteArrayInputStream(bytes); + } + return format(bais, offset); + } + + /** + * The formatter function is called repeatedly to read all of the bytes + * in the source and append the output. + * The source bytes are from the {@code ByteBuffer.position()} + * to the {@code ByteBuffer.limit()}. + * The position is not modified. + * All output is appended and flushed to the destination. + * + * @param source a ByteBuffer + * @return this HexPrinter + * @throws java.io.UncheckedIOException if an I/O error occurs + */ + public HexPrinter format(ByteBuffer source) { + return format(source, source.position(), source.limit()); + } + + /** + * The formatter function is called repeatedly to read all of the bytes + * and return a String. + * + * @param source a non-null array of bytes. + * @return the output as a non-null {@code String} + * @throws java.io.UncheckedIOException if an I/O error occurs + */ + public String toString(byte[] source) { + Objects.requireNonNull(source, "byte array must be non-null"); + return toString(new ByteArrayInputStream(source)); + } + + /** + * The formatter function is called repeatedly to read the bytes from offset + * for length and return a String. + * Only {@code length} bytes starting at the {@code offset} are formatted. + * + * @param source a non-null array of bytes. + * @param offset the offset into the array to start + * @param length the length of bytes in the array to format + * @return the output as a non-null {@code String} + * @throws java.io.UncheckedIOException if an I/O error occurs + */ + public String toString(byte[] source, int offset, int length) { + Objects.requireNonNull(source, "byte array must be non-null"); + StringBuilder sb = new StringBuilder(); + try (AnnotationWriter writer = + new AnnotationWriter(this, new ByteArrayInputStream(source, offset, length), + offset, sb)) { + writer.flush(); + return sb.toString(); + } + } + + /** + * The formatter function is called repeatedly to read all of the bytes + * and return a String. + *

+ * The {@code toString} method invokes the formatter to read bytes from the + * source and append the formatted sequence of byte values. + * As the bytes are read they are printed using the {@link #withBytesFormat} + * to fill the second field of the line. + * The output of the {@code formatter} fills the annotation field. + * A new line is started when either the byte values or annotation + * is filled to its respective width. The offset of the first byte on the line + * is inserted at the beginning of each line using {@link #withOffsetFormat(String)}. + *

+ * This method may block indefinitely reading from the input stream, + * or writing to the output stream. The behavior for the case where + * the input and/or output stream is asynchronously closed, + * or the thread interrupted during the transfer, is highly input + * and output stream specific, and therefore not specified. + *

+ * If an I/O error occurs reading from the input stream or + * writing to the output stream, then it may do so after some bytes + * have been read or written. Consequently the input stream + * may not be at end of stream and one, or both, streams may be + * in an inconsistent state. It is strongly recommended that both streams + * be promptly closed if an I/O error occurs. + * + * @param source an InputStream to read from, the stream not closed and + * is at end-of-file upon return. + * @return the output as a non-null {@code String} + * @throws java.io.UncheckedIOException if an I/O error occurs + */ + public String toString(InputStream source) { + Objects.requireNonNull(source, "InputStream must be non-null"); + StringBuilder sb = new StringBuilder(); + try (AnnotationWriter writer = + new AnnotationWriter(this, source, 0, sb)) { + writer.flush(); + return sb.toString(); + } + } + + /** + * The formatter function is called repeatedly to read the bytes + * from the offset for the length and return a String. + * The ByteBuffer position and limit are unused and not modified. + * + * @param source a ByteBuffer + * @param offset the offset in the ByteBuffer + * @param length the length in the ByteBuffer + * @return the output as a non-null {@code String} + * @throws java.io.UncheckedIOException if an I/O error occurs + */ + public String toString(ByteBuffer source, int offset, int length) { + Objects.requireNonNull(source, "ByteBuffer must be non-null"); + StringBuilder sb = new StringBuilder(); + ByteArrayInputStream bais; + if (source.hasArray() && !source.isReadOnly()) { + bais = new ByteArrayInputStream(source.array(), offset, length); + } else { + byte[] bytes = new byte[length]; + source.get(bytes, offset, length); + bais = new ByteArrayInputStream(bytes); + } + try (AnnotationWriter writer = + new AnnotationWriter(this, bais, offset, sb)) { + writer.flush(); + return sb.toString(); + } + } + + /** + * The formatter function is called repeatedly to read all of the bytes + * in the source and return a String. + * The source bytes are from the {@code ByteBuffer.position()} + * to the {@code ByteBuffer.limit()}. + * The position is not modified. + * + * @param source a ByteBuffer + * @return the output as a non-null {@code String} + * @throws java.io.UncheckedIOException if an I/O error occurs + */ + public String toString(ByteBuffer source) { + return toString(source, source.position(), source.limit()); + } + + /** + * Returns a new HexPrinter setting the format for the byte offset. + * The format string is specified by {@link String#format String format} + * including any delimiters. For example, {@code "%3x: "}. + * If the format is an empty string, there is no offset in the output. + * + * @param offsetFormat a new format string for the byte offset. + * @return a new HexPrinter + */ + public HexPrinter withOffsetFormat(String offsetFormat) { + Objects.requireNonNull(offsetFormat, "offsetFormat"); + return new HexPrinter(annoFormatter, offsetFormat, bytesFormat, bytesCount, + annoDelim, annoWidth, lineSeparator, dest); + } + + /** + * Returns a new HexPrinter setting the format for each byte value and + * the maximum number of byte values per line. + * The format string is specified by {@link String#format String format}, + * including any delimiters or padding. For example, {@code "%02x "}. + * If the byteFormat is an empty String, there are no byte values in the output. + * + * @param byteFormat a format string for each byte + * @param bytesCount the maximum number of byte values per line + * @return a new HexPrinter + */ + public HexPrinter withBytesFormat(String byteFormat, int bytesCount) { + Objects.requireNonNull(bytesFormat, "bytesFormat"); + return new HexPrinter(annoFormatter, offsetFormat, byteFormat, bytesCount, + annoDelim, annoWidth, lineSeparator, dest); + } + + /** + * Returns a new HexPrinter setting the line separator. + * The line separator can be set to an empty string or to + * a string to be added at the end of each line. It should include the line + * separator {@link System#lineSeparator()} if a line break is to be output. + * + * @param separator the line separator + * @return a new HexPrinter + */ + public HexPrinter withLineSeparator(String separator) { + return new HexPrinter(annoFormatter, offsetFormat, bytesFormat, bytesCount, + annoDelim, annoWidth, separator, dest); + } + + /** + * Returns a new HexPrinter setting the formatter. + * The widths, delimiters and other parameters are unchanged. + * + * @param formatter a non-null Formatter + * @return a new HexPrinter + */ + public HexPrinter formatter(Formatter formatter) { + Objects.requireNonNull(formatter, "Formatter must be non-null"); + return new HexPrinter(formatter, offsetFormat, bytesFormat, bytesCount, + annoDelim, annoWidth, lineSeparator, dest); + } + + /** + * Returns a new HexPrinter setting the formatter, delimiter, and width of the annotation. + * Note: The annotations may exceed the width. + * + * @param formatter a non-null Formatter + * @param delim a string delimiter for the annotation + * @param width the width of the annotation, non-negative + * @return a new HexPrinter + */ + public HexPrinter formatter(Formatter formatter, String delim, int width) { + Objects.requireNonNull(formatter, "formatter"); + Objects.requireNonNull(delim, "delim"); + return new HexPrinter(formatter, offsetFormat, bytesFormat, bytesCount, + delim, width, lineSeparator, dest); + } + + /** + * Returns a new HexPrinter setting the formatter to format a primitive type + * using the format string. + * The format string should include any pre or post spacing and delimiters. + *

+ * This is a convenience function equivalent to finding a formatter using + * {@link HexPrinter.Formatters#ofPrimitive}. + *

+ * + * @param primClass a primitive class, for example, {@code int.class} + * @param fmtString a {@link java.util.Formatter format string}. + * @return a new HexPrinter + * @throws IllegalArgumentException if the class is not a primitive class + */ + public HexPrinter formatter(Class primClass, String fmtString) { + Formatter formatter = getFormatter(primClass, fmtString); + return new HexPrinter(formatter, offsetFormat, bytesFormat, bytesCount, + annoDelim, annoWidth, lineSeparator, dest); + } + + /** + * Returns a formatter for the primitive type using the format string. + * The formatter reads a value of the primitive type from the stream + * and formats it using the format string. + * The format string includes any pre or post spacing and delimiters. + * + * @param primClass a primitive class, for example, {@code int.class} + * @param fmtString a {@link java.util.Formatter format string} + * @return a Formatter for the primitive type using the format string + */ + static Formatter getFormatter(Class primClass, String fmtString) { + return new PrimitiveFormatter(primClass, fmtString); + } + + /** + * Returns a string describing this HexPrinter. + * The string indicates the type of the destination and + * the formatting options. + * + * @return a String describing this HexPrinter + */ + public String toString() { + return "formatter: " + annoFormatter + + ", dest: " + dest.getClass().getName() + + ", offset: \"" + offsetFormat + + "\", bytes: " + bytesCount + + " x \"" + bytesFormat + "\"" + + ", delim: \"" + annoDelim + "\"" + + ", width: " + annoWidth + + ", nl: \"" + expand(lineSeparator) + "\""; + } + + private String expand(String sep) { + return sep.replace("\n", "\\n") + .replace("\r", "\\r"); + } + + private static class PrimitiveFormatter implements Formatter { + + private final Class primClass; + private final String fmtString; + + PrimitiveFormatter(Class primClass, String fmtString) { + Objects.requireNonNull(primClass, "primClass"); + Objects.requireNonNull(fmtString, "fmtString"); + if (!primClass.isPrimitive()) + throw new IllegalArgumentException("Not a primitive type: " + primClass.getName()); + this.primClass = primClass; + this.fmtString = fmtString; + } + + public void annotate(DataInputStream in, Appendable out) throws IOException { + if (primClass == byte.class) { + int v = in.readByte(); + out.append(String.format(fmtString, v)); + } else if (primClass == boolean.class) { + boolean v = in.readByte() != 0; + out.append(String.format(fmtString, v)); + } else if (primClass == short.class | primClass == char.class) { + int v = in.readShort(); + out.append(String.format(fmtString, v)); + } else if (primClass == float.class) { + float v = in.readFloat(); + out.append(String.format(fmtString, v)); + } else if (primClass == int.class) { + int v = in.readInt(); + out.append(String.format(fmtString, v)); + } else if (primClass == double.class) { + double v = in.readDouble(); + out.append(String.format(fmtString, v)); + } else if (primClass == long.class) { + long v = in.readLong(); + out.append(String.format(fmtString, v)); + } else { + throw new AssertionError("missing case on primitive class"); + } + } + + public String toString() { + return "(" + primClass.getName() + ", \"" + fmtString + "\")"; + } + } + + /** + * Formatter function reads bytes from a stream and + * appends a readable annotation to the output destination. + *

+ * Each invocation of the {@link #annotate annotate} method reads and annotates + * a single instance of its protocol or data type. + *

+ * Built-in formatting functions are provided in the {@link Formatters} class. + *

+ * As described by the {@link HexPrinter#toString(InputStream)} method, + * the {@link #annotate annotate} method is called to read bytes and produce + * the descriptive annotation. + *

+ * For example, a custom lambda formatter to read a float value (4 bytes) and + * print as a floating number could be written as a static method. + *

{@code
+     *     // Format 4 bytes read from the input as a float 3.4.
+     *     static void annotate(DataInputStream in, Appendable out) throws IOException {
+     *         float f = in.readFloat();
+     *         out.append(String.format("%3.4f, ", f));
+     *     }
+     *
+     *     byte[] bytes = new byte[] {00 00 00 00 3f 80 00 00 40 00 00 00 40 40 00 00};
+     *     HexPrinter pp = HexPrinter.simple()
+     *         .withBytesFormat("%02x ", 8)
+     *         .formatter(Example::annotate)
+     *         .format(bytes);
+     *
+     * Result:
+     *     0: 00 00 00 00 3f 80 00 00  // 0.0000, 1.0000,
+     *     8: 40 00 00 00 40 40 00 00  // 2.0000, 3.0000,
+     * }
+ * + *

+ * The details of the buffering and calling of the formatter {@code annotate} + * methods is roughly as follows. + * The bytes read by the {@code annotate} method are logically buffered + * for each line of output. + * The {@code annotate} method writes its description of the bytes read + * to the output, this output is also buffered. + * When the number of bytes read exceeds the + * {@link #withBytesFormat(String, int) byte values count per line}, + * the buffered output exceeds the + * {@link #formatter(Formatter, String, int) width of the annotation field}, + * or a new line {@code "\n"} character is found in the output then + * a line of output is assembled and written to the destination Appendable. + * The formatter's {@code annotate} method is called repeatedly + * until the input is completely consumed or an exception is thrown. + * Any remaining buffered bytes or description are flushed to the destination Appendable. + */ + @FunctionalInterface + public interface Formatter { + + /** + * Read bytes from the input stream and append a descriptive annotation + * to the output destination. + * + * @param in a DataInputStream + * @param out an Appendable for the output + * @throws IOException if an I/O error occurs + */ + void annotate(DataInputStream in, Appendable out) throws IOException; + } + + /** + * Built-in formatters for printable byte, ASCII, UTF-8 and primitive types. + * Formatters for primitive types and different formatting options + * can be found by calling {@link #ofPrimitive(Class, String)}. + */ + public enum Formatters implements Formatter { + /** + * Read a byte and if it is ASCII write it, + * otherwise, write its mnemonic or its decimal value. + */ + PRINTABLE, + /** + * Read a byte, if it is ASCII write it, otherwise write a ".". + */ + ASCII, + /** + * Read a modified UTF-8 string and write it. + */ + UTF8, + /** + * Read a byte and write nothing. + */ + NONE; + + public void annotate(DataInputStream in, Appendable out) throws IOException { + switch (this) { + case PRINTABLE: bytePrintable(in, out); break; + case ASCII: byteASCII(in, out); break; + case UTF8: utf8Parser(in, out); break; + case NONE: byteNoneParser(in, out); break; + } + } + + /** + * Read a byte and write it as ASCII if it is printable, + * print its mnemonic if it is a control character, + * and print its decimal value otherwise. + * A space separator character is appended for control and decimal values. + * + * @param in a DataInputStream + * @param out an Appendable to write to + * @throws IOException if an I/O error occurs + */ + static void bytePrintable(DataInputStream in, Appendable out) throws IOException { + int v = in.readUnsignedByte(); + if (v < 32) { + out.append("\\").append(CONTROL_MNEMONICS[v]); + } else if (v < 126 && Character.isDefined(v)) { + out.append((char) v); + } else { + out.append("\\").append(Integer.toString(v, 10)); + } + } + + /** + * Read a byte and write it as ASCII if it is printable, otherwise print ".". + * + * @param in a DataInputStream + * @param out an Appendable to write to + * @throws IOException if an I/O error occurs + */ + static void byteASCII(DataInputStream in, Appendable out) throws IOException { + int v = in.readUnsignedByte(); + if (Character.isDefined(v)) { + out.append((char) v); + } else { + out.append('.'); + } + } + + /** + * Read a modified UTF-8 string and write it to the output destination. + * + * @param in a DataInputStream + * @param out an Appendable to write the output to + * @throws IOException if an I/O error occurs + */ + static void utf8Parser(DataInputStream in, Appendable out) throws IOException { + out.append(in.readUTF()).append(" "); + } + + /** + * Read a a byte and write nothing. + * + * @param in a DataInputStream + * @param out an Appendable to write the output to + * @throws IOException if an I/O error occurs + */ + static void byteNoneParser(DataInputStream in, Appendable out) throws IOException { + in.readByte(); + } + + /** + * Returns a {@code Formatter} for a primitive using the format string. + * The format string includes any pre or post spacing or delimiters. + * A value of the primitive is read using the type specific methods + * of {@link DataInputStream}, formatted using the format string, and + * written to the output. + * + * @param primClass a primitive class, for example, {@code int.class} + * @param fmtString a {@link java.util.Formatter format string}. + * @return a Formatter + */ + public static Formatter ofPrimitive(Class primClass, String fmtString) { + Objects.requireNonNull(primClass, "primClass"); + Objects.requireNonNull(fmtString, "fmtString"); + return new PrimitiveFormatter(primClass, fmtString); + } + } + + /** + * Internal implementation of the annotation output and processor of annotated output. + * Created for each new input source and discarded after each use. + * An OffsetInputStream is created to buffer and count the input bytes. + * + */ + private static final class AnnotationWriter extends CharArrayWriter { + private final transient OffsetInputStream source; + private final transient DataInputStream in; + private final transient int baseOffset; + private final transient HexPrinter params; + private final transient int bytesColWidth; + private final transient int annoWidth; + private final transient Appendable dest; + + /** + * Construct a new AnnotationWriter to process the source into the destination. + * Initializes the DataInputStream and marking of the input to keep track + * of bytes as they are read by the formatter. + * @param params formatting parameters + * @param source source InputStream + * @param baseOffset initial offset + * @param dest destination Appendable + */ + AnnotationWriter(HexPrinter params, InputStream source, int baseOffset, Appendable dest) { + this.params = params; + this.baseOffset = baseOffset; + Objects.requireNonNull(source, "Source is null"); + this.source = new OffsetInputStream(source); + this.source.mark(1024); + this.in = new DataInputStream(this.source); + this.bytesColWidth = params.bytesCount * String.format(params.bytesFormat, 255).length(); + this.annoWidth = params.annoWidth; + this.dest = dest; + } + + @Override + public void write(int c) { + super.write(c); + checkFlush(); + } + + @Override + public void write(char[] c, int off, int len) { + super.write(c, off, len); + for (int i = 0; i < len; i++) { + if (c[off+i] == '\n') { + process(); + return; + } + } + checkFlush(); + } + + @Override + public void write(String str, int off, int len) { + super.write(str, off, len); + if (str.indexOf('\n') >=0 ) + process(); + else + checkFlush(); + } + + private void checkFlush() { + if (size() > annoWidth) + process(); + } + + /** + * The annotation printing function is called repeatedly to read all of the bytes + * in the source stream and annotate the stream. + * The annotated output is appended to the output dest or buffered. + *

+ * The HexPrinter is not closed and can be used as a template + * to create a new formatter with a new Source or different formatting + * options. + *

+ */ + @Override + public void flush() { + try { + while (true) { + if (source.markedByteCount() >= params.bytesCount) + process(); + params.annoFormatter.annotate(in, this); + if (source.markedByteCount() > 256) { + // Normally annotations would cause processing more often + // Guard against overrunning the mark/reset buffer. + process(); + } + } + } catch (IOException ioe) { + process(); + if (!(ioe instanceof EOFException)) { + throw new UncheckedIOException(ioe); + } + } catch (UncheckedIOException uio) { + process(); // clear out the buffers + throw uio; + } + } + + /** + * Merge the buffered stream of annotations with the formatted bytes + * and append them to the dest. + *

+ * The annotation mapping function has read some bytes and buffered + * some output that corresponds to those bytes. + * The un-formatted bytes are in the OffsetInputStream after the mark. + * The stream is reset and the bytes are read again. + * Each line of the produced one line at a time to the dest. + * The byte offset is formatted according to the offsetFormat. + * The bytes after the mark are read and formatted using the bytesFormat + * and written to the dest up to the bytesWidth. + * The annotation stream is appended to the dest, but only up to the + * first newline (if any). The alignment between the annotated stream + * and the formatted bytes is approximate. + * New line characters in the annotation cause a new line to be started + * without regard to the number of formatted bytes. The column of formatted + * bytes may be incomplete. + */ + private void process() { + String info = toString(); + reset(); + int count = source.markedByteCount(); + try { + source.reset(); + long binColOffset = source.byteOffset(); + while (count > 0 || info.length() > 0) { + dest.append(String.format(params.offsetFormat, binColOffset + baseOffset)); + int colWidth = 0; + int byteCount = Math.min(params.bytesCount, count); + for (int i = 0; i < byteCount; i++) { + int b = source.read(); + if (b == -1) + throw new IllegalStateException("BUG"); + String s = String.format(params.bytesFormat, b); + colWidth += s.length(); + dest.append(s); + } + binColOffset += byteCount; + count -= byteCount; + + // Pad out the bytes column to its width + dest.append(" ".repeat(Math.max(0, bytesColWidth - colWidth))); + dest.append(params.annoDelim); + + // finish a line and prepare for next line + // Add a line from annotation buffer + if (info.length() > 0) { + int nl = info.indexOf('\n'); + if (nl < 0) { + dest.append(info); + info = ""; + } else { + dest.append(info, 0, nl); + info = info.substring(nl + 1); + } + } + dest.append(params.lineSeparator); + } + } catch (IOException ioe) { + try { + dest.append("\nIOException during annotations: ") + .append(ioe.getMessage()) + .append("\n"); + } catch (IOException ignore) { + // ignore + } + } + // reset the mark for the next line + source.mark(1024); + } + } + + /** + * Buffered InputStream that keeps track of byte offset. + */ + private static final class OffsetInputStream extends BufferedInputStream { + private long byteOffset; + private long markByteOffset; + + OffsetInputStream(InputStream in) { + super(in); + byteOffset = 0; + markByteOffset = 0; + } + + long byteOffset() { + return byteOffset; + } + + @Override + public void reset() throws IOException { + super.reset(); + byteOffset = markByteOffset; + } + + @Override + public synchronized void mark(int readlimit) { + super.mark(readlimit); + markByteOffset = byteOffset; + } + + int markedByteCount() { + if (markpos < 0) + return 0; + return pos - markpos; + } + + @Override + public int read() throws IOException { + int b = super.read(); + if (b >= 0) + byteOffset++; + return b; + } + + @Override + public long skip(long n) throws IOException { + long size = super.skip(n); + byteOffset += size; + return size; + } + + @Override + public int read(byte[] b) throws IOException { + int size = super.read(b); + byteOffset += Math.max(size, 0); + return size; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + int size = super.read(b, off, len); + byteOffset += Math.max(size, 0); + return size; + } + } +} diff --git a/test/lib/jdk/test/lib/net/HttpHeaderParser.java b/test/lib/jdk/test/lib/net/HttpHeaderParser.java new file mode 100644 index 00000000000..9a55d28f4a9 --- /dev/null +++ b/test/lib/jdk/test/lib/net/HttpHeaderParser.java @@ -0,0 +1,390 @@ +/* + * Copyright (c) 2022, 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. + */ + +package jdk.test.lib.net; + +import java.io.IOException; +import java.io.InputStream; +import java.net.ProtocolException; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import static java.util.Objects.requireNonNull; + +public class HttpHeaderParser { + private static final char CR = '\r'; + private static final char LF = '\n'; + private static final char HT = '\t'; + private static final char SP = ' '; + // ABNF primitives defined in RFC 7230 + private static boolean[] tchar = new boolean[256]; + private static boolean[] fieldvchar = new boolean[256]; + + static { + char[] allowedTokenChars = + ("!#$%&'*+-.^_`|~0123456789" + + "abcdefghijklmnopqrstuvwxyz" + + "ABCDEFGHIJKLMNOPQRSTUVWXYZ").toCharArray(); + for (char c : allowedTokenChars) { + tchar[c] = true; + } + for (char c = 0x21; c <= 0xFF; c++) { + fieldvchar[c] = true; + } + fieldvchar[0x7F] = false; // a little hole (DEL) in the range + } + + private StringBuilder sb = new StringBuilder(); + + private Map > headerMap = new LinkedHashMap<>(); + private List keyList = new ArrayList<>(); + private String requestOrStatusLine; + private int responseCode; + private boolean eof; + + + + enum State { INITIAL, + STATUS_OR_REQUEST_LINE, + STATUS_OR_REQUEST_LINE_FOUND_CR, + STATUS_OR_REQUEST_LINE_FOUND_LF, + STATUS_OR_REQUEST_LINE_END, + STATUS_OR_REQUEST_LINE_END_CR, + STATUS_OR_REQUEST_LINE_END_LF, + HEADER, + HEADER_FOUND_CR, + HEADER_FOUND_LF, + HEADER_FOUND_CR_LF, + HEADER_FOUND_CR_LF_CR, + FINISHED } + + private HttpHeaderParser.State state = HttpHeaderParser.State.INITIAL; + + public HttpHeaderParser() { + } + + + public HttpHeaderParser(InputStream is) throws IOException, ProtocolException { + parse(is); + } + + public Map> getHeaderMap() { + return headerMap; + } + + public List getHeaderValue(String key) { + if(headerMap.containsKey(key.toLowerCase(Locale.ROOT))) { + return headerMap.get(key.toLowerCase(Locale.ROOT)); + } + return null; + } + public List getValue(int id) { + String key = keyList.get(id); + return headerMap.get(key); + } + + public String getRequestDetails() { + return requestOrStatusLine; + } + + /** + * Parses HTTP/1.X status-line or request-line and headers from the given input stream. + * @param input Containing the input stream of bytes representing request or response header data + * @return true if the end of the headers block has been reached + */ + public boolean parse(InputStream input) throws IOException { + requireNonNull(input, "null input"); + while (canContinueParsing()) { + switch (state) { + case INITIAL : state = HttpHeaderParser.State.STATUS_OR_REQUEST_LINE; break; + case STATUS_OR_REQUEST_LINE : readResumeStatusLine(input); break; + case STATUS_OR_REQUEST_LINE_FOUND_CR: case STATUS_OR_REQUEST_LINE_FOUND_LF : readStatusLineFeed(input); break; + case STATUS_OR_REQUEST_LINE_END : maybeStartHeaders(input); break; + case STATUS_OR_REQUEST_LINE_END_CR: case STATUS_OR_REQUEST_LINE_END_LF : maybeEndHeaders(input); break; + case HEADER : readResumeHeader(input); break; + case HEADER_FOUND_CR: case HEADER_FOUND_LF : resumeOrLF(input); break; + case HEADER_FOUND_CR_LF : resumeOrSecondCR(input); break; + case HEADER_FOUND_CR_LF_CR : resumeOrEndHeaders(input); break; + default : throw new InternalError("Unexpected state: " + state); + } + } + return state == HttpHeaderParser.State.FINISHED; + } + + private boolean canContinueParsing() { + // some states don't require any input to transition + // to the next state. + switch (state) { + case FINISHED : return false; + case STATUS_OR_REQUEST_LINE_FOUND_LF: STATUS_OR_REQUEST_LINE_END_LF: HEADER_FOUND_LF : return true; + default : return !eof; + } + } + + /** + * Returns a character (char) corresponding to the next byte in the + * input, interpreted as an ISO-8859-1 encoded character. + *

+ * The ISO-8859-1 encoding is a 8-bit character coding that + * corresponds to the first 256 Unicode characters - from U+0000 to + * U+00FF. UTF-16 is backward compatible with ISO-8859-1 - which + * means each byte in the input should be interpreted as an unsigned + * value from [0, 255] representing the character code. + * + * @param input a {@code InputStream} containing input stream of Bytes. + * @return the next byte in the input, interpreted as an ISO-8859-1 + * encoded char + * @throws IOException + * if an I/O error occurs. + */ + private char get(InputStream input) throws IOException { + int c = input.read(); + if(c < 0) + eof = true; + return (char)(c & 0xFF); + } + + private void readResumeStatusLine(InputStream input) throws IOException { + char c; + while ((c = get(input)) != CR && !eof) { + if (c == LF) break; + sb.append(c); + } + if (c == CR) { + state = HttpHeaderParser.State.STATUS_OR_REQUEST_LINE_FOUND_CR; + } else if (c == LF) { + state = HttpHeaderParser.State.STATUS_OR_REQUEST_LINE_FOUND_LF; + } + } + + private void readStatusLineFeed(InputStream input) throws IOException { + char c = state == HttpHeaderParser.State.STATUS_OR_REQUEST_LINE_FOUND_LF ? LF : get(input); + if (c != LF) { + throw protocolException("Bad trailing char, \"%s\", when parsing status line, \"%s\"", + c, sb.toString()); + } + requestOrStatusLine = sb.toString(); + sb = new StringBuilder(); + if (!requestOrStatusLine.startsWith("HTTP/1.")) { + if(!requestOrStatusLine.startsWith("GET") && !requestOrStatusLine.startsWith("POST") && + !requestOrStatusLine.startsWith("PUT") && !requestOrStatusLine.startsWith("DELETE") && + !requestOrStatusLine.startsWith("OPTIONS") && !requestOrStatusLine.startsWith("HEAD") && + !requestOrStatusLine.startsWith("PATCH") && !requestOrStatusLine.startsWith("CONNECT")) { + throw protocolException("Invalid request Or Status line: \"%s\"", requestOrStatusLine); + } else { //This is request + System.out.println("Request is :"+requestOrStatusLine); + } + } else { //This is response + if (requestOrStatusLine.length() < 12) { + throw protocolException("Invalid status line: \"%s\"", requestOrStatusLine); + } + try { + responseCode = Integer.parseInt(requestOrStatusLine.substring(9, 12)); + } catch (NumberFormatException nfe) { + throw protocolException("Invalid status line: \"%s\"", requestOrStatusLine); + } + // response code expected to be a 3-digit integer (RFC-2616, section 6.1.1) + if (responseCode < 100) { + throw protocolException("Invalid status line: \"%s\"", requestOrStatusLine); + } + } + state = HttpHeaderParser.State.STATUS_OR_REQUEST_LINE_END; + } + + private void maybeStartHeaders(InputStream input) throws IOException { + assert state == HttpHeaderParser.State.STATUS_OR_REQUEST_LINE_END; + assert sb.length() == 0; + char c = get(input); + if(!eof) { + if (c == CR) { + state = HttpHeaderParser.State.STATUS_OR_REQUEST_LINE_END_CR; + } else if (c == LF) { + state = HttpHeaderParser.State.STATUS_OR_REQUEST_LINE_END_LF; + } else { + sb.append(c); + state = HttpHeaderParser.State.HEADER; + } + } + } + + private void maybeEndHeaders(InputStream input) throws IOException { + assert state == HttpHeaderParser.State.STATUS_OR_REQUEST_LINE_END_CR || state == HttpHeaderParser.State.STATUS_OR_REQUEST_LINE_END_LF; + assert sb.length() == 0; + char c = state == HttpHeaderParser.State.STATUS_OR_REQUEST_LINE_END_LF ? LF : get(input); + if (c == LF) { + state = HttpHeaderParser.State.FINISHED; // no headers + } else { + throw protocolException("Unexpected \"%s\", after status line CR", c); + } + } + + private void readResumeHeader(InputStream input) throws IOException { + assert state == HttpHeaderParser.State.HEADER; + assert !eof; + char c = get(input); + while (!eof) { + if (c == CR) { + state = HttpHeaderParser.State.HEADER_FOUND_CR; + break; + } else if (c == LF) { + state = HttpHeaderParser.State.HEADER_FOUND_LF; + break; + } + if (c == HT) + c = SP; + sb.append(c); + c = get(input); + } + } + + private void addHeaderFromString(String headerString) throws ProtocolException { + assert sb.length() == 0; + int idx = headerString.indexOf(':'); + if (idx == -1) + return; + String name = headerString.substring(0, idx); + + // compatibility with HttpURLConnection; + if (name.isEmpty()) return; + + if (!isValidName(name)) { + throw protocolException("Invalid header name \"%s\"", name); + } + String value = headerString.substring(idx + 1).trim(); + if (!isValidValue(value)) { + throw protocolException("Invalid header value \"%s: %s\"", name, value); + } + + keyList.add(name); + headerMap.computeIfAbsent(name.toLowerCase(Locale.US), + k -> new ArrayList<>()).add(value); + } + + private void resumeOrLF(InputStream input) throws IOException { + assert state == HttpHeaderParser.State.HEADER_FOUND_CR || state == HttpHeaderParser.State.HEADER_FOUND_LF; + char c = state == HttpHeaderParser.State.HEADER_FOUND_LF ? LF : get(input); + if (!eof) { + if (c == LF) { + state = HttpHeaderParser.State.HEADER_FOUND_CR_LF; + } else if (c == SP || c == HT) { + sb.append(SP); // parity with MessageHeaders + state = HttpHeaderParser.State.HEADER; + } else { + sb = new StringBuilder(); + sb.append(c); + state = HttpHeaderParser.State.HEADER; + } + } + } + + private void resumeOrSecondCR(InputStream input) throws IOException { + assert state == HttpHeaderParser.State.HEADER_FOUND_CR_LF; + char c = get(input); + if (!eof) { + if (c == CR || c == LF) { + if (sb.length() > 0) { + // no continuation line - flush + // previous header value. + String headerString = sb.toString(); + sb = new StringBuilder(); + addHeaderFromString(headerString); + } + if (c == CR) { + state = HttpHeaderParser.State.HEADER_FOUND_CR_LF_CR; + } else { + state = HttpHeaderParser.State.FINISHED; + } + } else if (c == SP || c == HT) { + assert sb.length() != 0; + sb.append(SP); // continuation line + state = HttpHeaderParser.State.HEADER; + } else { + if (sb.length() > 0) { + // no continuation line - flush + // previous header value. + String headerString = sb.toString(); + sb = new StringBuilder(); + addHeaderFromString(headerString); + } + sb.append(c); + state = HttpHeaderParser.State.HEADER; + } + } + } + + private void resumeOrEndHeaders(InputStream input) throws IOException { + assert state == HttpHeaderParser.State.HEADER_FOUND_CR_LF_CR; + char c = get(input); + if (!eof) { + if (c == LF) { + state = HttpHeaderParser.State.FINISHED; + } else { + throw protocolException("Unexpected \"%s\", after CR LF CR", c); + } + } + } + + private ProtocolException protocolException(String format, Object ... args) { + return new ProtocolException(String.format(format, args)); + } + + /* + * Validates a RFC 7230 field-name. + */ + public boolean isValidName(String token) { + for (int i = 0; i < token.length(); i++) { + char c = token.charAt(i); + if (c > 255 || !tchar[c]) { + return false; + } + } + return !token.isEmpty(); + } + + /* + * Validates a RFC 7230 field-value. + * + * "Obsolete line folding" rule + * + * obs-fold = CRLF 1*( SP / HTAB ) + * + * is not permitted! + */ + public boolean isValidValue(String token) { + for (int i = 0; i < token.length(); i++) { + char c = token.charAt(i); + if (c > 255) { + return false; + } + if (c == ' ' || c == '\t') { + continue; + } else if (!fieldvchar[c]) { + return false; // forbidden byte + } + } + return true; + } +} diff --git a/test/lib/jdk/test/lib/util/CoreUtils.java b/test/lib/jdk/test/lib/util/CoreUtils.java new file mode 100644 index 00000000000..432115746af --- /dev/null +++ b/test/lib/jdk/test/lib/util/CoreUtils.java @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2020, 2023, 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. + */ + +package jdk.test.lib.util; + +import jdk.test.lib.Asserts; +import jdk.test.lib.Platform; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +import jtreg.SkippedException; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.Scanner; +import java.util.zip.GZIPInputStream; + +public class CoreUtils { + + private static final String RUN_SHELL_NO_LIMIT = "ulimit -c unlimited && "; + + /** + * Returns a {@code ulimit} command that will allow for an unlimited core file size + * if the platform supports it. + * + * @return {@code String} for the ulimit command if supported by the platform, + * otherwise {@code null}. + */ + private static String getCoreUlimitCommand() { + String result = null; + try { + OutputAnalyzer output = ProcessTools.executeProcess("sh", "-c", RUN_SHELL_NO_LIMIT + "ulimit -c"); + if (output.getExitValue() != 0) { + result = null; + } else if (!output.getStdout().contains("unlimited")) { + result = null; + } else { + result = RUN_SHELL_NO_LIMIT; // success + } + } catch (Throwable t) { + System.out.println("Exception in getCoreUlimitCommand(): " + t.toString()); + result = null; + } + System.out.println("Run test with ulimit -c: " + + (result == null ? "default" : "unlimited")); + return result; + } + + /** + * Return a {@code ProcessBuilder} that has been prefixed with + * a {@code ulimit} command to allow for an unlimited core file size. + * + * @param pb {@code ProcessBuilder} to prefix with the ulimit command + * @return New {@code ProcessBuilder} with prefixed {@code ulimit} command if + * supported. Otherwise the passed in {@code ProcessBuilder} is returned. + */ + public static ProcessBuilder addCoreUlimitCommand(ProcessBuilder pb) { + String cmd = ProcessTools.getCommandLine(pb); + String ulimitCmd = getCoreUlimitCommand(); + if (ulimitCmd == null) { + return pb; + } else { + if (Platform.isWindows()) { + // In order to launch on Windows using "sh -c", we need to first + // convert the path to use forward slashes and do some extra quoting. + cmd = cmd.replace('\\', '/').replace(";", "\\;").replace("|", "\\|"); + } + return new ProcessBuilder("sh", "-c", ulimitCmd + cmd); + } + } + + /** + * Find the path to the core file mentioned in the output and return its path. + * + * @param crashOutputString {@code String} to search in for the core file path + * @return Location of core file if found in the output, otherwise {@code null}. + */ + public static String getCoreFileLocation(String crashOutputString) throws IOException { + unzipCores(new File(".")); + + // Find the core file + String coreFileLocation = parseCoreFileLocationFromOutput(crashOutputString); + if (coreFileLocation != null) { + Asserts.assertGT(new File(coreFileLocation).length(), 0L, "Unexpected core size"); + System.out.println("Found core file: " + coreFileLocation); + return coreFileLocation; // success! + } else { + System.out.println("Core file not found. Trying to find a reason why..."); + } + + // See if we can figure out the likely reason the core file was not found. + // Throw SkippedException if appropriate. + if (Platform.isOSX()) { + File coresDir = new File("/cores"); + if (!coresDir.isDirectory()) { + throw new RuntimeException(coresDir + " is not a directory"); + } + // The /cores directory is usually not writable on macOS 10.15 + if (!coresDir.canWrite()) { + throw new SkippedException("Directory \"" + coresDir + "\" is not writable"); + } + if (Platform.isHardenedOSX()) { + if (Platform.getOsVersionMajor() > 10 || + (Platform.getOsVersionMajor() == 10 && Platform.getOsVersionMinor() >= 15)) + { + // We can't generate cores files with hardened binaries on OSX 10.15 and later. + throw new SkippedException("Cannot produce core file with hardened binary on OSX 10.15 and later"); + } + } else { + // codesign has to add entitlements using the plist. If this is not present we might not generate a core file. + if (!Platform.hasOSXPlistEntries()) { + throw new SkippedException("Cannot produce core file with binary having no plist entitlement entries"); + } + } + } else if (Platform.isLinux()) { + // Check if a crash report tool is installed. + File corePatternFile = new File(CORE_PATTERN_FILE_NAME); + try (Scanner scanner = new Scanner(corePatternFile)) { + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + line = line.trim(); + System.out.println(line); + if (line.startsWith("|")) { + System.out.println( + "\nThis system uses a crash report tool ($cat /proc/sys/kernel/core_pattern).\n" + + "Core files might not be generated. Please reset /proc/sys/kernel/core_pattern\n" + + "to enable core generation. Skipping this test."); + throw new SkippedException("This system uses a crash report tool"); + } + } + } + } + throw new RuntimeException("Couldn't find core file location in: '" + crashOutputString + "'"); + } + + private static final String CORE_PATTERN_FILE_NAME = "/proc/sys/kernel/core_pattern"; + private static final String LOCATION_STRING = "location: "; + + private static String parseCoreFileLocationFromOutput(String crashOutputString) { + System.out.println("crashOutputString = [" + crashOutputString + "]"); + if(crashOutputString == null || crashOutputString.equals("")) { + return null; + } + // Find the line of output that contains LOCATION_STRING + Asserts.assertTrue(crashOutputString.contains(LOCATION_STRING), + "Output doesn't contain the location of core file."); + String stringWithLocation = Arrays.stream(crashOutputString.split("\\r?\\n")) + .filter(str -> str.contains(LOCATION_STRING)) + .findFirst() + .get(); + stringWithLocation = stringWithLocation.substring(stringWithLocation + .indexOf(LOCATION_STRING) + LOCATION_STRING.length()); + System.out.println("getCoreFileLocation found stringWithLocation = " + stringWithLocation); + + // Find the core file name in the output. + String coreWithPid; + if (stringWithLocation.contains("or ") && !Platform.isWindows()) { + Matcher m = Pattern.compile("or.* ([^ ]+[^\\)])\\)?").matcher(stringWithLocation); + if (!m.find()) { + throw new RuntimeException("Couldn't find path to core inside location string"); + } + coreWithPid = m.group(1); + } else { + coreWithPid = stringWithLocation.trim(); + } + if (new File(coreWithPid).exists()) { + return coreWithPid; + } + + // Look for file named "core" in the cwd. + String justCore = Paths.get("core").toString(); + if (new File(justCore).exists()) { + return justCore; + } + + // Look for the core file name found in the output, but do so in the cwd. + Path coreWithPidPath = Paths.get(coreWithPid); + String justFile = coreWithPidPath.getFileName().toString(); + if (new File(justFile).exists()) { + return justFile; + } + + // Look for file named "core" in the path to the core file found in the output. + Path parent = coreWithPidPath.getParent(); + if (parent != null) { + String coreWithoutPid = parent.resolve("core").toString(); + if (new File(coreWithoutPid).exists()) { + return coreWithoutPid; + } + } + return null; + } + + private static void unzipCores(File dir) { + File[] gzCores = dir.listFiles((directory, name) -> name.matches("core(\\.\\d+)?\\.gz")); + for (File gzCore : gzCores) { + String coreFileName = gzCore.getName().replace(".gz", ""); + System.out.println("Unzipping core into " + coreFileName); + try (GZIPInputStream gzis = new GZIPInputStream(Files.newInputStream(gzCore.toPath()))) { + Files.copy(gzis, Paths.get(coreFileName)); + } catch (IOException e) { + throw new SkippedException("Not able to unzip file: " + gzCore.getAbsolutePath(), e); + } + } + } + + public static String getAlwaysPretouchArg(boolean withCore) { + // macosx-aarch64 has an issue where sometimes the java heap will not be dumped to the + // core file. Using -XX:+AlwaysPreTouch fixes the problem. + if (withCore && Platform.isOSX() && Platform.isAArch64()) { + return "-XX:+AlwaysPreTouch"; + } else { + return "-XX:-AlwaysPreTouch"; + } + } + +}