jtreg-jtreg-7.4-1/000077500000000000000000000000001461415321300137465ustar00rootroot00000000000000jtreg-jtreg-7.4-1/.gitignore000066400000000000000000000000531461415321300157340ustar00rootroot00000000000000/build/ /.idea/ /webrev .DS_Store .src-rev jtreg-jtreg-7.4-1/.hgignore000066400000000000000000000001131461415321300155440ustar00rootroot00000000000000^(build|dist)/ nbproject/private/ plugins/idea/.idea/ plugins/idea/build/ jtreg-jtreg-7.4-1/.hgtags000066400000000000000000000034571461415321300152350ustar00rootroot000000000000009f51ef22f00a3d5b681472cacf3ce15868073103 jtreg4.1-b01 2cf779985e18ba2f79aaec88f543be9efecf352f jtreg4.1-b02 bd7a3ed1210fa61f92f066c65d5e589e2aa26813 jtreg4.1-b03 cbc1f04a52ea2488e8dc7715fc59a5a122be9851 jtreg4.1-b04 46b8c02be3b356c7f953dbfa18246b357b5e7101 jtreg4.1-b05 d47a6e238c3e0f6d8ca1a6640c182be14c45eab2 jtreg-4.1-b06 d47a6e238c3e0f6d8ca1a6640c182be14c45eab2 jtreg4.1-b06 8ab579624a503e1df21841070ae5f869c301de8f jtreg4.1-b07 d47a6e238c3e0f6d8ca1a6640c182be14c45eab2 jtreg-4.1-b06 0000000000000000000000000000000000000000 jtreg-4.1-b06 e08a5e0b79ba57743222bbea19c0bdb142968769 jtreg4.1-b08 c54815dea64cf7b011f8473c18d54a86b9a9d5af jtreg4.1-b09 8c3179c3ebdab7df35b8e9907bd8ad8bc5a9f9f8 jtreg4.1-b10 04f40c388713f11c1cfb2094556d4b024b9ab939 jtreg4.1-b11 79705dae19e74b0693cda9ece8eaf0984159ab97 jtreg4.1-b12 5e994d1f9840ba39b82977a56e02c4f702a1dcbd jtreg4.1-b13 1159c9f96a4470dec79e6fa71b4f1a4895c4b20f jtreg4.2-b01 dbccea90c34dacf7e0824d5e3d3e9e1e930a103a jtreg4.2-b02 45590e2d6af12da44cc160764a9b552516be8440 jtreg4.2-b03 585f794e105997ab44109d70dbaa1c072b03afcc jtreg4.2-b04 4b0cd55e7741825de6ea79e9d4338d2972460678 jtreg4.2-b05 2d96b4cf02660b1580542379d77492f68d3ca73b jtreg4.2-b06 26d8a4a47674c4ca304b9e290dccca1dd1c7224f jtreg4.2-b07 cce0ac75e87864ed365a420fb836a4430421ab0f jtreg4.2-b08 684f12eef4a8c2f42afe2abe3d79eead72efcc5f jtreg4.2-b09 746c6d1328721541d3b16154c25a0179fbf53f7c jtreg4.2-b10 a13ec77e7adcc4c9ed434e664abc350abaacc045 jtreg4.2-b11 652902f7fb0ed0b4f307d61a799caf50a6e609be jtreg4.2-b12 7a38f21e077821a5015792e85b3793c90c81b866 jtreg4.2-b13 ec37d2900cd42987270f98423a60eb6297bdc37b jtreg4.2-b14 d5a9216fad5ca01002e18526be2c31cafb43e178 jtreg4.2-b15 deee95d5d8ff6406b77c0d5b9297736eb7c98c6d jtreg4.2-b16 03c4dff80b0f55865c6e5fe0aa8ea94d0ca1a2ac jtreg5.0-b01 95aa601b8100c6c56a14d35cfe493372214b1d94 jtreg5.1-b01 jtreg-jtreg-7.4-1/.jcheck/000077500000000000000000000000001461415321300152535ustar00rootroot00000000000000jtreg-jtreg-7.4-1/.jcheck/conf000066400000000000000000000010671461415321300161270ustar00rootroot00000000000000[general] project=code-tools comments=lax jbs=CODETOOLS [checks] error=author,committer,reviewers,merge,issues,executable,symlink,message,whitespace [repository] tags=jtreg(?:4\.1-b[0-9]{2}|5\.[01]-b[0-9]{2}|6|-[6789](?:\.[0-9]+)*\+[0-9]+) branches= [census] version=0 domain=openjdk.org [checks "whitespace"] files=.*\.java|.*\.m|.*\.mm|.*\.gmk|.*\.m4|.*\.ac|Makefile ignore-tabs=.*\.gmk|Makefile [checks "merge"] message=Merge [checks "reviewers"] reviewers=1 ignore=duke [checks "committer"] role=committer [checks "issues"] pattern=^(79[0-9]{5}): (\S.*)$ jtreg-jtreg-7.4-1/CHANGELOG.md000066400000000000000000000245511461415321300155660ustar00rootroot00000000000000## [Unreleased](https://git.openjdk.org/jtreg/compare/jtreg-7.4+1...master) _nothing noteworthy, yet_ ## [7.4](https://git.openjdk.org/jtreg/compare/jtreg-7.3.1+1...jtreg-7.4+1) * jtreg now verifies ProblemList files [CODETOOLS-7903659](https://bugs.openjdk.org/browse/CODETOOLS-7903659) * jtreg no longer ignores VM exit code when test process reports status with "STATUS: " line [CODETOOLS-7903621](https://bugs.openjdk.org/browse/CODETOOLS-7903621) * Use SOURCE_BUILD_EPOCH to suppport reproducible builds [CODETOOLS-7903539](https://bugs.openjdk.org/browse/CODETOOLS-7903539) * Updated jtreg to bundle JUnit 5.10.2 [CODETOOLS-7903578](https://bugs.openjdk.org/browse/CODETOOLS-7903578) * jtreg, when communicating with the AgentServer in agentvm mode, will now bind to loopback address. [CODETOOLS-7903686](https://bugs.openjdk.org/browse/CODETOOLS-7903686) * jtreg, in certain cases, would incorrectly report a test as PASSED when the test process would exit with a non-zero exit code. [CODETOOLS-7903621](https://bugs.openjdk.org/browse/CODETOOLS-7903621) ## [7.3.1](https://git.openjdk.org/jtreg/compare/jtreg-7.3+1...jtreg-7.3.1+1) * Fixed setting default environment variables on Windows * [CODETOOLS-7903515](https://bugs.openjdk.org/browse/CODETOOLS-7903515) ## [7.3](https://git.openjdk.org/jtreg/compare/jtreg-7.2+1...jtreg-7.3+1) * Updated set of default environment variables set for tests on Unix-like platforms. * Includes `DBUS_SESSION_BUS_ADDRESS`, `WAYLAND_DISPLAY`, and `XDG-*` [CODETOOLS-7903400](https://bugs.openjdk.org/browse/CODETOOLS-7903400) * Updated external dependencies. * Guice to 5.1.0 [CODETOOLS-7903468](https://bugs.openjdk.org/browse/CODETOOLS-7903468) * JCommander to 1.82 [CODETOOLS-7903469](https://bugs.openjdk.org/browse/CODETOOLS-7903469) * Fixed output-related issues. * AgentServer log() does not flush [CODETOOLS-7903470](https://bugs.openjdk.org/browse/CODETOOLS-7903470) * System.out and System.err messages are missing in jtr file when a test times out in agentvm mode [CODETOOLS-7903441](https://bugs.openjdk.org/browse/CODETOOLS-7903441) * Timeout refired %s times message confusing [CODETOOLS-7902485](https://bugs.openjdk.org/browse/CODETOOLS-7902485) * Fixed race-condition when running tests with a multi-module setup * [CODETOOLS-7903507](https://bugs.openjdk.org/browse/CODETOOLS-7903507) ## [7.2](https://git.openjdk.org/jtreg/compare/jtreg-7.1.1+1...jtreg-7.2+1) * Improved support for JUnit Jupiter. * Update jtreg to bundle JUnit 5.9.2 [CODETOOLS-7903406](https://bugs.openjdk.org/browse/CODETOOLS-7903406) * Improve reporting for errors in JUnit's lifecycle methods [CODETOOLS-7903430](https://bugs.openjdk.org/browse/CODETOOLS-7903430) * Improved support for TestNG. * Support `test.query` for TestNG tests [CODETOOLS-7903414](https://bugs.openjdk.org/browse/CODETOOLS-7903414) * Generate all debugging info when compiling `jtreg` [CODETOOLS-7903393](https://bugs.openjdk.org/browse/CODETOOLS-7903393) * RISC-V Port has been integrated into JDK mainline * Set `simpleArch` to `riscv64` when `os.arch` is `riscv64` [CODETOOLS-7903138](https://bugs.openjdk.org/browse/CODETOOLS-7903138) * Fix incorrect format for version in error message [CODETOOLS-7903398](https://bugs.openjdk.org/browse/CODETOOLS-7903398) * Add options -testThreadFactory and -testThreadFactoryPath to allow the use of a custom thread factory, to be used to create the thread to run a test. * [CODETOOLS-7903373](https://bugs.openjdk.org/browse/CODETOOLS-79033734) ## [7.1.1](https://git.openjdk.org/jtreg/compare/jtreg-7.1+1...jtreg-7.1.1+1) * Summary reporter getter is now thread-safe. * [CODETOOLS-7903390](https://bugs.openjdk.org/browse/CODETOOLS-7903390) ## [7.1](https://git.openjdk.org/jtreg/compare/jtreg-7+1...jtreg-7.1+1) * Improved support for JUnit Jupiter. * Avoid using TestNG mixed mode. [CODETOOLS-7903264](https://bugs.openjdk.org/browse/CODETOOLS-7903264) * Support JUnit tests in a system module. [CODETOOLS-7903260](https://bugs.openjdk.org/browse/CODETOOLS-7903260) * Support executing a single method. [CODETOOLS-7903267](https://bugs.openjdk.org/browse/CODETOOLS-7903267) * Improve per-class reporting of JUnit tests, in `.jtr` file. [CODETOOLS-7903324](https://bugs.openjdk.org/browse/CODETOOLS-7903324) * Support a group of "all tests", represented by `.`. * [CODETOOLS-7903331](https://bugs.openjdk.org/browse/CODETOOLS-7903331) * Improve performance when writing reports; new reporting option `-report:files`. * [CODETOOLS-7903323](https://bugs.openjdk.org/browse/CODETOOLS-7903323) * Updates for building jtreg with recent JDKs. * [CODETOOLS-7903346](https://bugs.openjdk.org/browse/CODETOOLS-7903346) * Improve OS detection on Mac. * Use `sw_vers`. [CODETOOLS-7903294](https://bugs.openjdk.org/browse/CODETOOLS-7903294) * Check process exit code. [CODETOOLS-7903325](https://bugs.openjdk.org/browse/CODETOOLS-7903325) * Trace reasons to recompile extra property definition files. * [CODETOOLS-7903329](https://bugs.openjdk.org/browse/CODETOOLS-7903329) * FAQ updates. * Time taken to run tests. [CODETOOLS-7903261](https://bugs.openjdk.org/browse/CODETOOLS-7903261) * Accessing TestNG and JUnit libraries. [CODETOOLS-7903244](https://bugs.openjdk.org/browse/CODETOOLS-7903244) ## [7](https://git.openjdk.org/jtreg/compare/jtreg-6.2+1...jtreg-7+1) * Improved support for JUnit Jupiter. * Use JUnit Platform Launcher. [CODETOOLS-7903047](https://bugs.openjdk.org/browse/CODETOOLS-7903047) * Use JUnit uber-jar. [CODETOOLS-7903055](https://bugs.openjdk.org/browse/CODETOOLS-7903055) * Support MSYS2 for building jtreg on Windows. * [CODETOOLS-7903206](https://bugs.openjdk.org/browse/CODETOOLS-7903206) * `os.simpleArch` is `x64` for `linux-loongarch64`/`mips64`/`mips64el` in `@require` context. * [CODETOOLS-7903120](https://bugs.openjdk.org/browse/CODETOOLS-7903120) * Log start time for every action. * [CODETOOLS-7903183](https://bugs.openjdk.org/browse/CODETOOLS-7903183) * Update OS version check. * [CODETOOLS-7903184](https://bugs.openjdk.org/browse/CODETOOLS-7903184) * Support invocation via ToolProvider. * [CODETOOLS-7903097](https://bugs.openjdk.org/browse/CODETOOLS-7903097) * Report `os.*` system properties in `.jtr` file. * [CODETOOLS-7903044](https://bugs.openjdk.org/browse/CODETOOLS-7903044) ## [6.2](https://git.openjdk.org/jtreg/compare/jtreg-6.1+1...jtreg-6.2+1) * Provide system property or option to override timeout. * [CODETOOLS-7903083](https://bugs.openjdk.org/browse/CODETOOLS-7903083) * Updates for building jtreg with recent JDKs. * [CODETOOLS-7903073](https://bugs.openjdk.org/browse/CODETOOLS-7903073) * Add an FAQ entry for `javatest.maxOutputSize`. * [CODETOOLS-7903050](https://bugs.openjdk.org/browse/CODETOOLS-7903050) * Allow subtest ids with dashes and underscores. * [CODETOOLS-7903037](https://bugs.openjdk.org/browse/CODETOOLS-7903037) * jtreg should print stdout if JVM gathering properties fails. * [CODETOOLS-7903030](https://bugs.openjdk.org/browse/CODETOOLS-7903030) ## [6.1](https://git.openjdk.org/jtreg/compare/jtreg-6+1...jtreg-6.1+1) * Elapsed time of `MainAction` is including serialization wait time * [CODETOOLS-7902942](https://bugs.openjdk.org/browse/CODETOOLS-7902942) * Support building jtreg with recent JDKs. * [CODETOOLS-7902966](https://bugs.openjdk.org/browse/CODETOOLS-7902966) * [CODETOOLS-7902991](https://bugs.openjdk.org/browse/CODETOOLS-7902991) * Update/improve jcheck settings for jtreg repo. * [CODETOOLS-7902995](https://bugs.openjdk.org/browse/CODETOOLS-7902995) * Introduce support for `HEADLESS` to disable tests that require a display. * jtreg should not set a security manager for JDK 18. * [CODETOOLS-7902990](https://bugs.openjdk.org/browse/CODETOOLS-7902990) ## [6](https://git.openjdk.org/jtreg/compare/jtreg5.1-b01...jtreg-6+1) * Add support for `Automatic-Module-Name` in jar files. * Update versions of jtreg dependencies. * [CODETOOLS-7902791](https://bugs.openjdk.org/browse/CODETOOLS-7902791) * User modules can be used only in othervm. * [CODETOOLS-7902707](https://bugs.openjdk.org/browse/CODETOOLS-7902707) * Improve diagnostic output when failing to get version for JDK under test. * [CODETOOLS-7902748](https://bugs.openjdk.org/browse/CODETOOLS-7902748) * Initial support for new-style version numbers for jtreg. * Improve support for `@enablePreview`. * [CODETOOLS-7902754](https://bugs.openjdk.org/browse/CODETOOLS-7902754) * Move details of environment variables to new appendix. * Add FAQ reference to `doc/testing.md`. * Add support for explicit `-retain:lastRun`. ## [5.1](https://git.openjdk.org/jtreg/compare/jtreg5.0-b01...jtreg5.1-b01) * Update AsmTools to 7.0 b08; update JT Harness to 6.0-b11. * Add `test.name` to properties given to test. * [CODETOOLS-7902671](https://bugs.openjdk.org/browse/CODETOOLS-7902671) * Pass `test.*` to `requires.extraPropDefns` classes. * [CODETOOLS-7902336](https://bugs.openjdk.org/browse/CODETOOLS-7902336) * Add mean, standard deviation to agent stats. * Report jtreg version info to work directory. * Report agent pool statistics. * Improve version details for JT Harness and AsmTools. * Log Agent Pool activity to `agent.trace` file. * Catch output written to agent stdout (fd1) and stderr (fd2). * [CODETOOLS-7902657](https://bugs.openjdk.org/browse/CODETOOLS-7902657) * Log agent activity to files in the work directory. * [CODETOOLS-7902656](https://bugs.openjdk.org/browse/CODETOOLS-7902656) * Propagate client-side "id" to agent server. * [CODETOOLS-7902655](https://bugs.openjdk.org/browse/CODETOOLS-7902655) * Support `@enablePreview`. * [CODETOOLS-7902654](https://bugs.openjdk.org/browse/CODETOOLS-7902654) * Use https://git.openjdk.org for CODE_TOOLS_URL. * [CODETOOLS-7902637](https://bugs.openjdk.org/browse/CODETOOLS-7902637) * Ignore specified lines in `@compile/fail/ref=`. * [CODETOOLS-7902633](https://bugs.openjdk.org/browse/CODETOOLS-7902633) * Validate test group names. * [CODETOOLS-7902606](https://bugs.openjdk.org/browse/CODETOOLS-7902606) ## [5](https://git.openjdk.org/jtreg/compare/jtreg4.2-b16...jtreg5.0-b01) * Improve Cygwin detection by relaxing constraints on expected installation directory. * Incorrect handling of paths in smart action args for Windows. * [CODETOOLS-7902571](https://bugs.openjdk.org/browse/CODETOOLS-7902571) * Introduce `test.file`. * [CODETOOLS-7902545](https://bugs.openjdk.org/browse/CODETOOLS-7902545) jtreg-jtreg-7.4-1/CONTRIBUTING.md000066400000000000000000000003071461415321300161770ustar00rootroot00000000000000# Contributing to JTReg JTReg is part of the OpenJDK [CodeTools] Project. Please see for how to contribute. [CodeTools]: https://openjdk.org/projects/code-tools jtreg-jtreg-7.4-1/CONTRIBUTORS000066400000000000000000000010721461415321300156260ustar00rootroot00000000000000The following people have contributed to the development of jtreg. Original Author: Iris Clark Tag Specification: Mark Reinhold Currently Maintained As Part Of: OpenJDK CodeTools Project Other Early Contributors: Brian Kurotsuchi Dawn Phillips Jessica Mauvais John Rose Maurizio Cimadamore Kumar Srinivasan Since open-sourcing the code in 2006, and the use of first Mercurial and subsequently Git, the Contributors are tracked in the SCM metadata. For all recent contributors and contributions, see `git shortlog` or `git log`. jtreg-jtreg-7.4-1/COPYRIGHT000066400000000000000000000017421461415321300152450ustar00rootroot00000000000000Copyright (c) 1996, 2012, 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. jtreg-jtreg-7.4-1/LICENSE000066400000000000000000000455121461415321300147620ustar00rootroot00000000000000The GNU General Public License (GPL) Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. One line to give the program's name and a brief idea of what it does. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type 'show w'. This is free software, and you are welcome to redistribute it under certain conditions; type 'show c' for details. The hypothetical commands 'show w' and 'show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than 'show w' and 'show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program 'Gnomovision' (which makes passes at compilers) written by James Hacker. signature of Ty Coon, 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. "CLASSPATH" EXCEPTION TO THE GPL Certain source files distributed by Oracle America and/or its affiliates are subject to the following clarification and special exception to the GPL, but only where Oracle has expressly included in the particular source file's header the words "Oracle designates this particular file as subject to the "Classpath" exception as provided by Oracle in the LICENSE file that accompanied this code." Linking this library statically or dynamically with other modules is making a combined work based on this library. Thus, the terms and conditions of the GNU General Public License cover the whole combination. As a special exception, the copyright holders of this library give you permission to link this library with independent modules to produce an executable, regardless of the license terms of these independent modules, and to copy and distribute the resulting executable under terms of your choice, provided that you also meet, for each linked independent module, the terms and conditions of the license of that module. An independent module is a module which is not derived from or based on this library. If you modify this library, you may extend this exception to your version of the library, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. jtreg-jtreg-7.4-1/README.md000066400000000000000000000017541461415321300152340ustar00rootroot00000000000000# The Regression Test Harness for the OpenJDK platform: `jtreg` * For details on writing tests for `jtreg`, see [The JDK Test Framework: Tag Language Specification][tagspec]. * For details on building `jtreg`, see [doc/building.md](doc/building.md). * For additional details about `jtreg`, see [The `jtreg` FAQ][faq]. * For details on running JDK tests using the JDK _make test_ framework, see [Using "make test" (the run-test framework)][make-test]. [faq]: https://openjdk.org/jtreg/faq.html [tagspec]: https://openjdk.org/jtreg/tag-spec.html [make-test]: https://github.com/openjdk/jdk/blob/master/doc/testing.md ## Using IntelliJ IDEA The `jtreg` repo also contains a plugin for the IntelliJ IDEA IDE. This is a convenience plugin which adds `jtreg` capabilities to the IDE. With this plugin, OpenJDK developers can write, run, and debug `jtreg` tests without leaving their IDE environment. For more details, see the file [plugins/idea/README.md](plugins/idea/README.md) in this repo. jtreg-jtreg-7.4-1/doc/000077500000000000000000000000001461415321300145135ustar00rootroot00000000000000jtreg-jtreg-7.4-1/doc/building.md000066400000000000000000000164541461415321300166440ustar00rootroot00000000000000# Building The Regression Test Harness for the OpenJDK platform: `jtreg` (This information is also available at ) `jtreg` depends on a number of external components: JT Harness, TestNG, JUnit, AsmTools, and JCov. The fundamental way to build `jtreg` is with GNU make, specifying where to find those external components, but a script is also available that will download appropriate copies of those components before building `jtreg`. ## Building `jtreg` with the `build.sh` script This is the recommended way to build `jtreg`, for those that want a simple, basic way to build `jtreg`. *Note:* The _build.sh_ script supersedes the earlier _build-all.sh_ script. The script is intended to be run in a Unix-like shell, such as `bash` on Linux or Mac OS X, or with Cygwin, MSYS2, or WSL on Windows. At a minimum, you must either set the `JAVA_HOME` environment variable or specify the location of the JDK to be used to build `jtreg` with the `--jdk` command-line option. It must be a recent build of JDK 11 or later. % cd jtreg-root-directory % sh make/build.sh --jdk JDK-directory If your shell is not compatible with `bash`, you may need to invoke `bash` explicitly: % bash make/build.sh --jdk JDK-directory The script will create a `build` sub-directory, download and build dependencies, and finally build `jtreg` itself. The resulting image will be in _build/images/jtreg_ . If you have access to the public Internet, no environment variables need to be specified to get a standard build of `jtreg`. However, you can set environment variables used to define the location of dependencies to be downloaded. These are documented in _make/build.sh_ and are normally specified in _make/build-support/version-numbers_ and _make/build-support/*/version-numbers_ . ### Rebuilding faster with `build/make.sh` After you have run `make/build.sh` once, if you wish to rebuild after making some changes, you can run `build/make.sh`. It skips the steps to download and build the dependencies, and so should be significantly faster. ## Building `jtreg` with GNU Make If you don't want to use `build.sh` to build `jtreg`, you can invoke the makefile directly, or by writing and using your own alternative wrapper. The makefiles require a number of variables to be set, identifying the parts of all the dependencies. In general, there are two kinds of variable to be set for each dependency: the location of any jar files that may be required to use the component, and the location of any "legal notices" (such as license files) that may need to be included in the `jtreg` image. There are five dependencies that need to be made available. The following lists the variables that need to be set for each dependency. 1. [JT Harness] (JavaTest) * `JAVATEST_JAR`: a jar file containing the classes for JT Harness * `JTHARNESS_NOTICES`: any legal notices that may be required to use JT Harness 2. [AsmTools] * `ASMTOOLS_JAR`: a jar file containing the classes for AsmTools * `ASMTOOLS_NOTICES`: any legal notices that may be required to use AsmTools 3. [JCov] * `JCOV_JAR`: a jar file containing the main set classes for JCov tools * `JCOV_NETWORK_SAVER_JAR`: a jar file containing the classes to inject into a JVM to save coverage information * `JCOV_NOTICES`: any legal notices that may be required to use JCov 4. [JUnit] * `JUNIT_JARS`: a list of one or more jar files containing the classes for JUnit and its dependencies: the list may be a series of jar files or a singleton "uber-jar" * `JUNIT_NOTICES`: any legal notices that be required to use JUnit Consult the JUnit documentation to see if there are any additional dependencies that may be required when running JUnit. 5. [TestNG] * `TESTNG_JARS`: a list of one or more jar files containing the classes for TestNG and its dependencies: the list may be a series of jar files or a singleton "uber-jar" * `TESTNG_NOTICES`: any legal notices that be required to use TestNG Consult the TestNG documentation to see if there are any additional dependencies that may be required when running TestNG. In general, any jar files identified by `*_JAR` or `*_JARS` variables will be copied to the `lib` directory in the generated image. Any files identified by `*_NOTICES` variables will be copied to a component-specific subdirectory of the `legal` directory in the generated image. [AsmTools]: https://github.com/openjdk/asmtools [JCov]: https://github.com/openjdk/jcov [JT Harness]: https://github.com/openjdk/jtharness [JUnit]: https://junit.org/ [TestNG]: https://testng.org/ ## Running `jtreg` Self-Tests The tests can be invoked with individual make targets, or collectively via the `test` target. Individual make targets for self-tests are explained [here](../test/README.md#makefiles). For example, the [ControlTest.gmk](../test/ctrl/ControlTest.gmk) makefile has a `$(BUILDTESTDIR)/ControlTest.ok` target which runs one of the self-tests. In order to run that individual test, use a command such as the following: ```shell bash build/make.sh $(pwd)/build/test/ControlTest.ok ``` Some tests depend on specific versions of JDK being available, specified by the following variables: `JDK8HOME`, `JDK9HOME`, `JDK14HOME`, `JDK18HOME`. A test that requires any of these version of JDK will be skipped if the variable is not set. Some of the tests need to pop up windows while they execute. No interaction with these windows is normally required. Since this can be a problem on a headless server machine, and an annoyance on a personal workstation, the tests will attempt to use VNC to create a dummy X-server for use by the tests while they are running. Various implementations of VNC are available, such as from . Using VNC is optional; it is not required in order to run the tests. By default, VNC will be used if `vncserver` is found on your execution path, or if VNC_HOME points to an installed copy of VNC. To explicitly disable the use of VNC, set the VNC environment variable to one of false, off, no, or 0. Unless explicitly disabled, the tests will check the following: * You must have a password set in _$HOME/.vnc/passwd_. This is the standard location used by the vncserver command. * If you set the environment variable `VNC_HOME`, it will be prepended to your execution path to find vncserver. * vncserver must be on your execution path, after `VNC_HOME` has been added, if set. If the tests find any issue with using VNC, it will not be used. If VNC is used to create a dummy X server, the server will be terminated when the test is complete. The logic for using VNC is encapsulated within the script _make/display.sh_. # Contribution guidelines Contributors are encouraged to follow code style conventions in [Java Style Guidelines](https://cr.openjdk.org/~alundblad/styleguide/index-v6.html) where reasonable. Existing `jtreg` command-line options have a certain style due to their age, but new options should strive to follow [JEP 293: Guidelines for JDK Command-Line Tool Options](https://openjdk.org/jeps/293). For backwards compatibility, `jtreg` option names are case-insensitive. The `jtreg` codebase is very dependent on (jtharness)[https://github.com/openjdk/jtharness]. The two repos should most often be viewed together. This also places constraints on what changes can (easily) be made in jtreg. jtreg-jtreg-7.4-1/make/000077500000000000000000000000001461415321300146635ustar00rootroot00000000000000jtreg-jtreg-7.4-1/make/CheckJavaOSVersion.java000066400000000000000000000041351461415321300211600ustar00rootroot00000000000000/* * 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. */ /** * Checks the value of System.getProperty("os.version") against an expected value. * For more info, see * JDK-8253702: BigSur version number reported as 10.16, should be 11.nn * https://bugs.openjdk.org/browse/JDK-8253702 */ public class CheckJavaOSVersion { public static void main(String... args) { checkJavaOSVersion(args[0]); } private static void checkJavaOSVersion(String expectVersion) { String osVersion = System.getProperty("os.version"); if (!osVersion.startsWith(expectVersion)) { System.err.println("The version of JDK you are using does not report the OS version correctly."); System.err.println(" java.home: " + System.getProperty("java.home")); System.err.println(" java.version: " + System.getProperty("java.version")); System.err.println(" os.version: " + osVersion + " (expected: " + expectVersion + ")"); System.err.println("Use a more recent update of this version of JDK, or a newer version of JDK."); System.exit(1); } } } jtreg-jtreg-7.4-1/make/Defs.gmk000066400000000000000000000154661461415321300162600ustar00rootroot00000000000000# # Copyright (c) 1996, 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. Oracle designates this # particular file as subject to the "Classpath" exception as provided # by Oracle in the LICENSE file that accompanied this code. # # 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 host-specific defs, if any -include Defs-$(shell hostname).gmk # TOPDIR = .. # now set in Makefile ABSTOPDIR = $(shell cd $(TOPDIR); pwd) # clobber settings from user's environment JAVA_HOME= CLASSPATH= JAVA_COMPILER= LD_LIBRARY_PATH= #---------------------------------------------------------------------- # # Support for Cygwin and MSYS2 (which may identify as MSYS, MINGW32 or MINGW64 (the default)) SYSTEM_UNAME := $(shell uname) # Where is unwanted output to be delivered? # On Windows, MKS uses the special file "NUL", cygwin uses the customary unix file. ifeq ($(SYSTEM_UNAME), Windows_NT) DEV_NULL = NUL else DEV_NULL = /dev/null endif ifneq (,$(findstring CYGWIN,$(SYSTEM_UNAME))) USING_CYGWIN = true USING_CYGWIN_OR_USING_MSYS = true endif ifneq (,$(findstring MSYS,$(SYSTEM_UNAME))$(findstring MINGW,$(SYSTEM_UNAME))) USING_MSYS = true USING_CYGWIN_OR_USING_MSYS = true endif ifdef USING_CYGWIN_OR_USING_MSYS define FullPath $(shell cygpath -a -m $1 2> $(DEV_NULL)) endef define PosixPath $(shell cygpath -a -u $1 2> $(DEV_NULL)) endef else define FullPath $(abspath $1) endef define PosixPath $1 endef endif ifndef BUILDDIR BUILDDIR = $(TOPDIR)/build endif override BUILDDIR := $(call FullPath, $(BUILDDIR)) override JDKHOME := $(call FullPath, $(JDKHOME)) BUILDTESTDIR=$(BUILDDIR)/test #---------------------------------------------------------------------- # # Parameters to control what to build and test with. # Notices are optional or may be empty # The following are not optional ... ifndef JDKHOME $(error JDKHOME not set) endif ifndef JAVATEST_JAR $(error JAVATEST_JAR not set) endif ifndef ASMTOOLS_JAR $(error ASMTOOLS_JAR not set) endif ifndef JUNIT_JARS $(error JUNIT_JARS not set) endif ifndef TESTNG_JARS $(error TESTNG_JARS not set) endif # derived values JDKJAVA = $(JDKHOME)/bin/java JDKJAVAC = $(JDKHOME)/bin/javac JAR = $(JDKHOME)/bin/jar AGENT_JAVAC_SOURCE_TARGET = --release 8 TOOL_JAVAC_SOURCE_TARGET = --release 11 REGTEST_TOOL_PATCH_JAVA_BASE_OPTIONS = --patch-module java.base=$(JAVADIR) # for files needed to run agentvm and othervm tests (on platforms back to JDK 8) REGTEST_AGENT_JAVAC = $(JDKHOME)/bin/javac REGTEST_AGENT_JAVAC_OPTIONS = \ $(AGENT_JAVAC_SOURCE_TARGET) -Xlint:all,-options,-deprecation -Werror # for files needed for jtreg tool REGTEST_TOOL_JAVAC = $(JDKHOME)/bin/javac REGTEST_TOOL_JAVAC_OPTIONS = \ $(TOOL_JAVAC_SOURCE_TARGET) -Xlint:all,-options,-deprecation -Werror #----- Unix commands AWK = /usr/bin/awk CAT = /bin/cat CHMOD = /bin/chmod CP = /bin/cp DIFF = /usr/bin/diff ECHO = /bin/echo FIND = /usr/bin/find GREP := $(shell if [ -r /bin/grep ]; then echo /bin/grep ; else echo /usr/bin/grep ; fi ) LN = /bin/ln LS = /bin/ls MKDIR = /bin/mkdir MV = /bin/mv PANDOC := $(shell if [ -r /usr/bin/pandoc ]; then \ echo /usr/bin/pandoc ; \ elif [ -r /usr/local/bin/pandoc ]; then \ echo /usr/local/bin/pandoc ; \ elif [ -r /opt/homebrew/bin/pandoc ]; then \ echo /opt/homebrew/bin/pandoc ; \ else \ echo /bin/echo "pandoc not available" ; \ fi ) PERL = /usr/bin/perl PRINTF = /usr/bin/printf RM = /bin/rm -rf SED := $(shell if [ -r /bin/sed ]; then echo /bin/sed ; else echo /usr/bin/sed ; fi ) SH = /bin/sh SORT = /usr/bin/sort TEST = /usr/bin/test ifeq ($(SYSTEM_UNAME), Darwin) TIDY := $(shell if [ -r /usr/local/bin/tidy ]; then \ echo /usr/local/bin/tidy ; \ elif [ -r /opt/homebrew/bin/tidy ]; then \ echo /opt/homebrew/bin/tidy ; \ else \ echo /usr/bin/tidy ; \ fi ) else TIDY = /usr/bin/tidy endif TOUCH = /usr/bin/touch UNZIP = /usr/bin/unzip WC = /usr/bin/wc ZIP = /usr/bin/zip #---------------------------------------------------------------------- # # Identification of parts of the system SRCDIR = $(TOPDIR)/src JAVADIR = $(SRCDIR)/share/classes SRCDOCDIR = $(SRCDIR)/share/doc SRCJTDOCDIR = $(SRCDIR)/share/doc/javatest SRCJTREGDOCDIR = $(SRCDIR)/share/doc/javatest/regtest SRCSHAREBINDIR = $(SRCDIR)/share/bin TESTDIR = $(TOPDIR)/test CLASSDIR = $(BUILDDIR)/classes ABSCLASSDIR = $(cd $(CLASSDIR); pwd) IMAGES_DIR = $(BUILDDIR)/images JTREG_IMAGEDIR = $(IMAGES_DIR)/jtreg JTREG_IMAGEDOCDIR = $(JTREG_IMAGEDIR)/doc JTREG_IMAGEJARDIR = $(JTREG_IMAGEDIR)/lib ABS_JTREG_IMAGEJARDIR = $(shell cd $(JTREG_IMAGEJARDIR); pwd) # source bundle locations IMAGESRC_SRCDIR = $(IMAGESRC_TOPDIR)/src/share/classes #---------------------------------------------------------------------- # # Version tags # # BUILD_* variables are normally set (overridden) by RE builds BUILD_VERSION = 5.2 BUILD_MILESTONE = dev BUILD_NUMBER = b00 # don't eval dates here directly, because that leads to unstable builds #BUILD_YEAR:sh = /bin/date +"%Y" BUILD_YEAR_CMD = /bin/date '+%Y' #BUILD_DOCDATE:sh = /bin/date +"%B %d, %Y" BUILD_DOCDATE_CMD = /bin/date +'%B %d, %Y' #BUILD_ZIPDATE:sh = /bin/date '+%d %h %Y' BUILD_ZIPDATE_CMD = /bin/date '+%d %h %Y' BUILD_NONFCS_MILESTONE_sh = echo $(BUILD_MILESTONE) | sed -e 's/[fF][cC][sS]//' BUILD_NONFCS_MILESTONE = $(BUILD_NONFCS_MILESTONE_sh:sh) # munge the BUILD values suitable for use in the bundle name ZIPSFX_VERSION_sh = echo '$(BUILD_VERSION)' | sed -e 's|\([^0-9][^0-9]*\)|_|g' ZIPSFX_MILESTONE_sh = echo '$(BUILD_MILESTONE)' ZIPSFX_BUILD_sh = echo '$(BUILD_NUMBER)' ZIPSFX_NEWBUILD_sh = echo '$(BUILD_NUMBER)' | sed -e 's|[^[0-9]||g' | xargs printf "%d" ZIPSFX_DATE_sh = echo "`$(BUILD_ZIPDATE_CMD)`" | /usr/bin/tr -s '[A-Z] ' '[a-z]_' VERBOSE_ZIP_SUFFIX = $(shell $(ZIPSFX_VERSION_sh))-$(shell $(ZIPSFX_MILESTONE_sh))-bin-$(shell $(ZIPSFX_BUILD_sh))-$(shell $(ZIPSFX_DATE_sh)) ifdef BUILD_MILESTONE NEW_VERBOSE_ZIP_SUFFIX = $(BUILD_VERSION)-$(BUILD_MILESTONE)+$(shell $(ZIPSFX_NEWBUILD_sh))_bin else NEW_VERBOSE_ZIP_SUFFIX = $(BUILD_VERSION)+$(shell $(ZIPSFX_NEWBUILD_sh))_bin endif jtreg-jtreg-7.4-1/make/Makefile000066400000000000000000000066641461415321300163370ustar00rootroot00000000000000# # Copyright (c) 1999, 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. Oracle designates this # particular file as subject to the "Classpath" exception as provided # by Oracle in the LICENSE file that accompanied this code. # # 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. # TOPDIR = .. include Defs.gmk include Platform.gmk default: build all: build test #---------------------------------------------------------------------- include jtreg.gmk include $(TOPDIR)/test/*.gmk include $(TOPDIR)/test/*/*.gmk include Rules.gmk build: $(BUILDFILES) test: checkJavaOSVersion $(BUILDTESTDIR) $(INITIAL_TESTS) $(TESTS) $(FINAL_TESTS) count=`echo $+ | wc -w` ; \ echo "All ($${count}) selected tests completed successfully" quick-test: checkJavaOSVersion $(BUILDTESTDIR) $(INITIAL_TESTS) count=`echo $+ | wc -w` ; \ echo "All ($${count}) selected tests completed successfully" images: $(VERBOSEZIPFILES) new-images: $(NEWVERBOSEZIPFILES) clean: $(RM) $(BUILDDIR) clean-except-deps: for i in $(BUILDDIR)/* ; do \ case $$i in \ */deps ) ;; \ * ) $(RM) $$i ;; \ esac \ done clean-deps: $(RM) $(BUILDDIR)/deps clean-tests: $(RM) $(BUILDTESTDIR) .NO_PARALLEL: clean clean-except-deps clean-deps clean-tests sanity: ifdef JDK8HOME @echo "JDK8HOME = $(JDK8HOME)" endif ifdef JDK9HOME @echo "JDK9HOME = $(JDK9HOME)" endif ifdef JDK14HOME @echo "JDK14HOME = $(JDK14HOME)" endif ifdef JDK18HOME @echo "JDK18HOME = $(JDK18HOME)" endif @echo "JDKHOME = $(JDKHOME)" @echo "JAVATEST_HOME = $(JAVATEST_HOME)" ifneq ($(JTHARNESS_HOME), $(JAVATEST_HOME)) @echo "JTHARNESS_HOME = $(JTHARNESS_HOME)" endif @echo "JTHARNESS_NOTICES = $(JTHARNESS_NOTICES)" @echo "ASMTOOLS_JAR = $(ASMTOOLS_JAR)" @echo "ASMTOOLS_NOTICES = $(ASMTOOLS_NOTICES)" @echo "JUNIT_JARS = $(JUNIT_JARS)" @echo "JUNIT_NOTICES = $(JUNIT_NOTICES)" @echo "TESTNG_JARS = $(TESTNG_JARS)" @echo "TESTNG_NOTICES = $(TESTNG_NOTICES)" @echo "BUILD_VERSION = $(BUILD_VERSION)" @echo "BUILD_MILESTONE = $(BUILD_MILESTONE)" @echo "BUILD_NUMBER = $(BUILD_NUMBER)" #---------------------------------------------------------------------- $(BUILDTESTDIR): $(MKDIR) -p $@ #---------------------------------------------------------------------- checkJavaOSVersion: ifeq ($(OS_NAME), macosx) $(JDKJAVA) CheckJavaOSVersion.java $(OS_VERSION) endif #---------------------------------------------------------------------- .PHONY: default all build test images new-images clean sanity jtreg-jtreg-7.4-1/make/Platform.gmk000066400000000000000000000134641461415321300171570ustar00rootroot00000000000000# # Copyright (c) 1995, 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. Oracle designates this # particular file as subject to the "Classpath" exception as provided # by Oracle in the LICENSE file that accompanied this code. # # 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. # # This file is an extract from jdk/test/Makefile to model the logic # for determining the platform keys used for ProblemList.txt CUT = cut UNAME = uname # Get OS name from uname UNAME_S := $(shell $(UNAME) -s) # Commands to run on paths to make mixed paths for java on windows GETMIXEDPATH=$(ECHO) # Location of developer shared files SLASH_JAVA = /java # path separator PS = : # Platform specific settings ifeq ($(UNAME_S), SunOS) OS_NAME = solaris OS_ARCH := $(shell $(UNAME) -p) OS_VERSION := $(shell $(UNAME) -r) endif ifeq ($(UNAME_S), Linux) OS_NAME = linux OS_ARCH := $(shell $(UNAME) -m) # Check for unknown arch, try uname -p if uname -m says unknown ifeq ($(OS_ARCH),unknown) OS_ARCH := $(shell $(UNAME) -p) endif OS_VERSION := $(shell $(UNAME) -r) endif ifeq ($(UNAME_S), Darwin) OS_NAME = macosx OS_ARCH := $(shell $(UNAME) -m) OS_VERSION := $(shell defaults read loginwindow SystemVersionStampAsString) endif ifeq ($(OS_NAME),) OS_NAME = windows # GNU Make or MKS overrides $(PROCESSOR_ARCHITECTURE) to always # return "x86". Use the first word of $(PROCESSOR_IDENTIFIER) instead. ifeq ($(PROCESSOR_IDENTIFIER),) PROC_ARCH:=$(shell $(UNAME) -m) else PROC_ARCH:=$(word 1, $(PROCESSOR_IDENTIFIER)) endif OS_ARCH:=$(PROC_ARCH) SLASH_JAVA = J: EXESUFFIX = .exe # These need to be different depending on MKS or CYGWIN ifeq ($(findstring cygdrive,$(shell (cd C:/ && pwd))), ) GETMIXEDPATH = dosname -s OS_VERSION := $(shell $(UNAME) -r) else GETMIXEDPATH = cygpath -m -s OS_VERSION := $(shell $(UNAME) -s | $(CUT) -d'-' -f2) endif PS = ; endif EMPTY := SPACE := $(EMPTY) $(EMPTY) AS_CLASSPATH = $(subst $(SPACE),$(PS),$(strip $1)) # Only want major and minor numbers from os version OS_VERSION := $(shell $(ECHO) "$(OS_VERSION)" | $(CUT) -d'.' -f1,2) # Name to use for x86_64 arch (historically amd64, but should change someday) #OS_ARCH_X64_NAME:=amd64 OS_ARCH_X64_NAME:=x64 # Alternate arch names (in case this arch is known by a second name) # PROBLEM_LISTS may use either name. #OS_ARCH2-amd64:=x64 OS_ARCH2-x64:=amd64 # Try and use the arch names consistently OS_ARCH:=$(patsubst x64,$(OS_ARCH_X64_NAME),$(OS_ARCH)) OS_ARCH:=$(patsubst X64,$(OS_ARCH_X64_NAME),$(OS_ARCH)) OS_ARCH:=$(patsubst AMD64,$(OS_ARCH_X64_NAME),$(OS_ARCH)) OS_ARCH:=$(patsubst amd64,$(OS_ARCH_X64_NAME),$(OS_ARCH)) OS_ARCH:=$(patsubst x86_64,$(OS_ARCH_X64_NAME),$(OS_ARCH)) OS_ARCH:=$(patsubst 8664,$(OS_ARCH_X64_NAME),$(OS_ARCH)) OS_ARCH:=$(patsubst EM64T,$(OS_ARCH_X64_NAME),$(OS_ARCH)) OS_ARCH:=$(patsubst em64t,$(OS_ARCH_X64_NAME),$(OS_ARCH)) OS_ARCH:=$(patsubst intel64,$(OS_ARCH_X64_NAME),$(OS_ARCH)) OS_ARCH:=$(patsubst Intel64,$(OS_ARCH_X64_NAME),$(OS_ARCH)) OS_ARCH:=$(patsubst INTEL64,$(OS_ARCH_X64_NAME),$(OS_ARCH)) OS_ARCH:=$(patsubst IA64,ia64,$(OS_ARCH)) OS_ARCH:=$(patsubst X86,i586,$(OS_ARCH)) OS_ARCH:=$(patsubst x86,i586,$(OS_ARCH)) OS_ARCH:=$(patsubst i386,i586,$(OS_ARCH)) OS_ARCH:=$(patsubst i486,i586,$(OS_ARCH)) OS_ARCH:=$(patsubst i686,i586,$(OS_ARCH)) OS_ARCH:=$(patsubst 386,i586,$(OS_ARCH)) OS_ARCH:=$(patsubst 486,i586,$(OS_ARCH)) OS_ARCH:=$(patsubst 586,i586,$(OS_ARCH)) OS_ARCH:=$(patsubst 686,i586,$(OS_ARCH)) # Default ARCH_DATA_MODEL settings ARCH_DATA_MODEL-i586 = 32 ARCH_DATA_MODEL-$(OS_ARCH_X64_NAME) = 64 ARCH_DATA_MODEL-ia64 = 64 ARCH_DATA_MODEL-sparc = 32 ARCH_DATA_MODEL-sparcv9 = 64 # If ARCH_DATA_MODEL is not defined, try and pick a reasonable default ifndef ARCH_DATA_MODEL ARCH_DATA_MODEL:=$(ARCH_DATA_MODEL-$(OS_ARCH)) endif ifndef ARCH_DATA_MODEL ARCH_DATA_MODEL=32 endif # Platform directory name PLATFORM_OS = $(OS_NAME)-$(OS_ARCH) # Check ARCH_DATA_MODEL, adjust OS_ARCH accordingly on solaris ARCH_DATA_MODEL_ERROR= \ ARCH_DATA_MODEL=$(ARCH_DATA_MODEL) cannot be used with $(PLATFORM_OS) ifeq ($(ARCH_DATA_MODEL),64) ifeq ($(PLATFORM_OS),solaris-i586) OS_ARCH=$(OS_ARCH_X64_NAME) endif ifeq ($(PLATFORM_OS),solaris-sparc) OS_ARCH=sparcv9 endif ifeq ($(OS_ARCH),i586) x:=$(warning "WARNING: $(ARCH_DATA_MODEL_ERROR)") endif ifeq ($(OS_ARCH),sparc) x:=$(warning "WARNING: $(ARCH_DATA_MODEL_ERROR)") endif else ifeq ($(ARCH_DATA_MODEL),32) ifeq ($(OS_ARCH),$(OS_ARCH_X64_NAME)) x:=$(warning "WARNING: $(ARCH_DATA_MODEL_ERROR)") endif ifeq ($(OS_ARCH),ia64) x:=$(warning "WARNING: $(ARCH_DATA_MODEL_ERROR)") endif ifeq ($(OS_ARCH),sparcv9) x:=$(warning "WARNING: $(ARCH_DATA_MODEL_ERROR)") endif else x:=$(warning "WARNING: $(ARCH_DATA_MODEL_ERROR)") endif endif # Alternate OS_ARCH name (defaults to OS_ARCH) OS_ARCH2:=$(OS_ARCH2-$(OS_ARCH)) ifeq ($(OS_ARCH2),) OS_ARCH2:=$(OS_ARCH) endif jtreg-jtreg-7.4-1/make/Rules.gmk000066400000000000000000000105011461415321300164520ustar00rootroot00000000000000# # Copyright (c) 1996, 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. Oracle designates this # particular file as subject to the "Classpath" exception as provided # by Oracle in the LICENSE file that accompanied this code. # # 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. # #--------------------------------------------------------------------- # # Copy resources (*.properties) into classes directory from source tree $(CLASSDIR)/%.properties: $(JAVADIR)/%.properties $(RM) -f $@ $(MKDIR) -p $(@D) $(CP) $(@:$(CLASSDIR)/%=$(JAVADIR)/%) $@ $(CLASSDIR)/%.gif: $(JAVADIR)/%.gif $(RM) -f $@ $(MKDIR) -p $(@D) $(CP) $(@:$(CLASSDIR)/%=$(JAVADIR)/%) $@ $(CLASSDIR)/%.png: $(JAVADIR)/%.png $(RM) -f $@ $(MKDIR) -p $(@D) $(CP) $(@:$(CLASSDIR)/%=$(JAVADIR)/%) $@ $(CLASSDIR)/META-INF/services/%: $(JAVADIR)/META-INF/services/% $(RM) -f $@ $(MKDIR) -p $(@D) $(CP) $(@:$(CLASSDIR)/%=$(JAVADIR)/%) $@ #--------------------------------------------------------------------- $(CLASSDIR) $(BUILDDIR) $(BUILDDIR)/testClasses $(BUILDDIR)/testWork $(BUILDDIR)/testReport: $(MKDIR) -p $@ #---------------------------------------------------------------------- # # Build a JAR file containing the contents of any classes/* files # listed in the FILES.JAR.% # default copyright; override as necessary JAR_COPYRIGHT = -C $(TOPDIR) COPYRIGHT DATE_FMT = +%B %d, %Y ifdef SOURCE_DATE_EPOCH BUILD_DATE ?= $(shell LC_ALL=C date -u -d "@$(SOURCE_DATE_EPOCH)" "$(DATE_FMT)" 2>/dev/null || LC_ALL=C date -u -r "$(SOURCE_DATE_EPOCH)" "$(DATE_FMT)" 2>/dev/null || date -u "$(DATE_FMT)") else BUILD_DATE ?= $(shell date "$(DATE_FMT)") endif $(IMAGES_DIR)/%.jar: pkgsToFiles.sh $(RM) $@ $(@:$(IMAGES_DIR)/%.jar=$(BUILDDIR)/jarData/%) $(MKDIR) -p $(@D) $(MKDIR) -p $(@:$(IMAGES_DIR)/%.jar=$(BUILDDIR)/jarData/%) ( if [ -n "$(JAR_MAINCLASS)" ]; then echo "Main-class: $(JAR_MAINCLASS)" ; fi ; \ if [ -n "$(JAR_CLASSPATH)" ]; then echo "Class-Path: $(JAR_CLASSPATH)" ; fi ; \ echo "$(@F:%.jar=%)-Name: $(@F:%.jar=%)" ; \ if [ -n "$(BUILD_VERSION_STRING)" ]; then echo "$(@F:%.jar=%)-VersionString: $(BUILD_VERSION_STRING)" ; fi ; \ echo "$(@F:%.jar=%)-Version: $(BUILD_VERSION)" ; \ echo "$(@F:%.jar=%)-Milestone: $(BUILD_MILESTONE)" ; \ echo "$(@F:%.jar=%)-Build: $(BUILD_NUMBER)" ; \ echo "$(@F:%.jar=%)-BuildJavaVersion: `$(JDKJAVA) -fullversion 2>&1 | awk '{print $$NF}' | \ sed -e 's|^"\(.*\)"$$|Java(TM) 2 SDK, Version \1|'`" ; \ echo "$(@F:%.jar=%)-BuildDate: $(BUILD_DATE)" ; \ ) \ > $(@:$(IMAGES_DIR)/%.jar=$(BUILDDIR)/jarData/%/manifest.txt) sh pkgsToFiles.sh $(CLASSDIR) $($(@F:%.jar=PKGS.JAR.%)) > $(@:$(IMAGES_DIR)/%.jar=$(BUILDDIR)/jarData/%/includes.txt) $(JAR) -cmf $(@:$(IMAGES_DIR)/%.jar=$(BUILDDIR)/jarData/%/manifest.txt) $@ \ $(JAR_COPYRIGHT) \ @$(@:$(IMAGES_DIR)/%.jar=$(BUILDDIR)/jarData/%/includes.txt) \ $(patsubst $(CLASSDIR)/%,-C $(CLASSDIR) %,$(sort $(FILES.JAR.$(@F:%.jar=%)))) \ $(JAR_EXTRAS) $(CHMOD) a-w $@ #---------------------------------------------------------------------- # # Build zips with verbose names %-$(VERBOSE_ZIP_SUFFIX).zip: %.zip $(CP) $(@:%-$(VERBOSE_ZIP_SUFFIX).zip=%.zip) $@ %-$(NEW_VERBOSE_ZIP_SUFFIX).zip: %.zip $(RM) $@ $(LN) $(@:%-$(NEW_VERBOSE_ZIP_SUFFIX).zip=%.zip) $@ #---------------------------------------------------------------------- # # cancel implicit rules %: %.o %: %.obj %: %.dll %: %.c %: %.cc %: %.cpp %: %.C %: %.p %: %.f %: %.s %: %.F %: %.r %: %.S %: %.mod %: %.sh jtreg-jtreg-7.4-1/make/build-support/000077500000000000000000000000001461415321300174745ustar00rootroot00000000000000jtreg-jtreg-7.4-1/make/build-support/asmtools/000077500000000000000000000000001461415321300213355ustar00rootroot00000000000000jtreg-jtreg-7.4-1/make/build-support/asmtools/build.sh000066400000000000000000000057031461415321300227750ustar00rootroot00000000000000#!/bin/bash # # 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. Oracle designates this # particular file as subject to the "Classpath" exception as provided # by Oracle in the LICENSE file that accompanied this code. # # 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. # mydir="$(dirname ${BASH_SOURCE[0]})" log_module="$(basename "${BASH_SOURCE[0]}")" . "${mydir}/../build-common.sh" . "${mydir}/version-numbers" ASMTOOLS_SRC_TAG="${ASMTOOLS_SRC_TAG:-${DEFAULT_ASMTOOLS_SRC_TAG}}" ASMTOOLS_SRC_ARCHIVE_CHECKSUM="${ASMTOOLS_SRC_ARCHIVE_CHECKSUM:-${DEFAULT_ASMTOOLS_SRC_ARCHIVE_CHECKSUM}}" ANT_VERSION="${ANT_VERSION:-${DEFAULT_ANT_VERSION}}" ANT_ARCHIVE_CHECKSUM="${ANT_ARCHIVE_CHECKSUM:-${DEFAULT_ANT_ARCHIVE_CHECKSUM}}" setup_ant setup_asmtools_src() { check_arguments "${FUNCNAME}" 1 $# local dir="$1" local ASMTOOLS_LOCAL_SRC_ARCHIVE="${dir}/../source.zip" if [ "${ASMTOOLS_SRC_TAG}" = "tip" -o "${ASMTOOLS_SRC_TAG}" = "master" ]; then local BRANCH="master" get_archive_no_checksum "${CODE_TOOLS_URL_BASE}/asmtools/archive/${BRANCH}.zip" "${ASMTOOLS_LOCAL_SRC_ARCHIVE}" "${dir}" ASMTOOLS_SRC_DIR="${dir}/asmtools-${BRANCH}" else get_archive "${CODE_TOOLS_URL_BASE}/asmtools/archive/${ASMTOOLS_SRC_TAG}.zip" "${ASMTOOLS_LOCAL_SRC_ARCHIVE}" "${dir}" "${ASMTOOLS_SRC_ARCHIVE_CHECKSUM}" ASMTOOLS_SRC_DIR="${dir}/asmtools-${ASMTOOLS_SRC_TAG}" fi } build_asmtools() { check_arguments "${FUNCNAME}" 0 $# local ASMTOOLS_SRC_DIR_BASE="${BUILD_DIR}/src" setup_asmtools_src "${ASMTOOLS_SRC_DIR_BASE}" local ASMTOOLS_DIST="${BUILD_DIR}/build" "${ANT}" -DBUILD_DIR="$(native_path "${ASMTOOLS_DIST}")" -f "$(native_path "${ASMTOOLS_SRC_DIR}/build/build.xml")" ASMTOOLS_JAR="${ASMTOOLS_DIST}/binaries/lib/asmtools.jar" ASMTOOLS_LICENSE="${ASMTOOLS_SRC_DIR}/LICENSE" } build_asmtools if [ ! x"$BUILD_RESULTS_FILE" = x"" ]; then mkdir -p "$(dirname "${BUILD_RESULTS_FILE}")" cat > "${BUILD_RESULTS_FILE}" << EOF ASMTOOLS_JAR="${ASMTOOLS_JAR}" ASMTOOLS_LICENSE="${ASMTOOLS_LICENSE}" EOF fi jtreg-jtreg-7.4-1/make/build-support/asmtools/version-numbers000066400000000000000000000025611461415321300244220ustar00rootroot00000000000000# # 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. Oracle designates this # particular file as subject to the "Classpath" exception as provided # by Oracle in the LICENSE file that accompanied this code. # # 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. # DEFAULT_ASMTOOLS_SRC_TAG=7.0-b09 DEFAULT_ASMTOOLS_SRC_ARCHIVE_CHECKSUM=604f5e1aad1912968781dc72a1f86043e4e2dc20 DEFAULT_ANT_VERSION=1.10.8 DEFAULT_ANT_ARCHIVE_CHECKSUM=dbe187ce2963f9df8a67de8aaff3b0a437d06978 jtreg-jtreg-7.4-1/make/build-support/build-common.sh000066400000000000000000000200351461415321300224150ustar00rootroot00000000000000# # 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. Oracle designates this # particular file as subject to the "Classpath" exception as provided # by Oracle in the LICENSE file that accompanied this code. # # 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. # log_message() { local level="$1" shift echo "[${log_module}][${level}] $@" } error() { log_message "ERROR" "$@" } info() { log_message "INFO" "$@" } ## # Helper used to ensure the correct number of arguments is passed to bash functions check_arguments() { local name="$1" local expected="$2" local actual="$3" if [ ! "${expected}" = "${actual}" ]; then error "Incorrect number of arguments to function '${name}' (expecting ${expected} but got ${actual})" exit 1 fi } ## # Print an absolute path abspath() { check_arguments "${FUNCNAME}" 1 $# local path="$1" if [[ ${path} = /* ]]; then echo "${path}" else echo "$PWD/${path}" fi } ## # Set up the checksum tool to use # setup_shasum() { if [ -n "${SHASUM:-}" ]; then return fi if [ -n "$(which sha1sum)" ]; then SHASUM="sha1sum" SHASUM_OPTIONS="" elif [ -n "$(which shasum)" ]; then SHASUM="shasum" SHASUM_OPTIONS="-a 1" else error "Can't find shasum or sha1sum" exit 1 fi } native_path() { check_arguments "${FUNCNAME}" 1 $# if [ $CYGWIN_OR_MSYS -eq 1 ]; then echo $(cygpath -w $1); else echo "$1"; fi } mixed_path() { check_arguments "${FUNCNAME}" 1 $# if [ $CYGWIN_OR_MSYS -eq 1 ]; then echo $(cygpath -m $1); else echo "$1"; fi } ## # Download a file using wget # # wget options can be provided through the WGET_OPTIONS environment # variable # download_using_wget() { check_arguments "${FUNCNAME}" 2 $# local url="$1" local destfile="$2" set +e "${WGET}" ${WGET_OPTIONS} "${url}" -O "${destfile}" ret=$? if [ ! ${ret} = 0 ]; then error "wget exited with exit code ${ret}" exit 1 fi set -e } ## # Download a file using curl # # curl options can be provided through the CURL_OPTIONS environment # variable # download_using_curl() { check_arguments "${FUNCNAME}" 2 $# local url="$1" local destfile="$2" set +e "${CURL}" ${CURL_OPTIONS} "${url}" -o "${destfile}" ret=$? if [ ! ${ret} = 0 ]; then error "curl exited with exit code ${ret}" exit 1 fi set -e } ## # Download a file # # Will attempt to skip the download if the SKIP_DOWNLOAD environment # variable is set and the destination file already exists # download() { check_arguments "${FUNCNAME}" 2 $# local url="$1" local destfile="$2" if [ "${SKIP_DOWNLOAD:-}" != "" -a -r "${destfile}" ]; then info "Skipping download of ${url}..." return fi info "Downloading ${url} to ${destfile}" mkdir -p "$(dirname "${destfile}")" if [ -n "${WGET}" ]; then download_using_wget "${url}" "${destfile}" elif [ -n "${CURL}" ]; then download_using_curl "${url}" "${destfile}" else error "Cannot find a suitable tool for downloading fils (tried 'wget' and 'curl')" exit 1 fi } ## # Checksum a file # checksum() { check_arguments "${FUNCNAME}" 2 $# local file="$1" local expected="$2" if [ -n "${SKIP_CHECKSUM_CHECK:-}" ]; then return fi if [ x"${expected}" = x"" ]; then error "Expected checksum unexpectedly empty.." exit 1 fi local actual="$("${SHASUM}" ${SHASUM_OPTIONS} "${dest}" | awk '{ print $1; }')" if [ ! x"${actual}" = x"${expected}" ]; then error "Checksum mismatch for ${dest}:" error "Expected: ${expected}" error "Actual : ${actual}" exit 1 fi } ## # Download and checksum a file # download_and_checksum() { check_arguments "${FUNCNAME}" 3 $# local url="$1" local dest="$2" local shasum="$3" download "${url}" "${dest}" checksum "${dest}" "${shasum}" } ## # Unpack an archive # unpack() { check_arguments "${FUNCNAME}" 2 $# local file="$1" local unpackdir="$2" info "Unpacking $file in $unpackdir" ( mkdir -p "${unpackdir}" case ${file} in *.tar.gz) "${TAR_CMD}" -xzf "$1" -C "${unpackdir}" ;; *.zip) "${UNZIP_CMD}" -q "$1" -d "${unpackdir}" ;; *) error "Unknown archive type for file '${file}'" exit 1 esac ) } ## # Download and unpack an archive without performing a checksum check # get_archive_no_checksum() { check_arguments "${FUNCNAME}" 3 $# local url="$1" local destfile="$2" local unpackdir="$3" rm -rf "${unpackdir}"/* download "${url}" "${destfile}" unpack "${destfile}" "${unpackdir}" } ## # Download, checksum, and unpack an archive # get_archive() { check_arguments "${FUNCNAME}" 4 $# local url="$1" local destfile="$2" local unpackdir="$3" local shasum="$4" rm -rf "${unpackdir}"/* download_and_checksum "${url}" "${destfile}" "${shasum}" unpack "${destfile}" "${unpackdir}" } ## # Set up the ANT (and possibly ANT_JAR) environment variable(s) # setup_ant() { check_arguments "${FUNCNAME}" 0 $# if [ -n "${ANT:-}" ]; then return fi if [ -z "${ANT_ARCHIVE_URL:-}" ]; then if [ -n "${ANT_ARCHIVE_URL_BASE:-}" ]; then ANT_ARCHIVE_URL="${ANT_ARCHIVE_URL_BASE}/apache-ant-${ANT_VERSION}-bin.zip" fi fi local ANT_DEPS_DIR="${DEPS_DIR}/ant" if [ -n "${ANT_ARCHIVE_URL:-}" ]; then local ANT_LOCAL_ARCHIVE_FILE="${DEPS_DIR}/$(basename "${ANT_ARCHIVE_URL}")" get_archive "${ANT_ARCHIVE_URL}" "${ANT_LOCAL_ARCHIVE_FILE}" "${ANT_DEPS_DIR}" "${ANT_ARCHIVE_CHECKSUM}" ANT="$(find "${ANT_DEPS_DIR}" -path '*/bin/ant')" ANT_JAR="$(dirname "${ANT}")/../lib/ant.jar" return fi error "Neither ANT_ARCHIVE_URL or ANT_ARCHIVE_URL_BASE is set" exit 1 } set -e set -u if [ -z "${mydir:-}" ]; then error "mydir not set in caller (line/file): $(caller)" exit 1 fi if [ -z "${log_module:-}" ]; then error "log_module not set in caller (line/file): $(caller)" exit 1 fi ROOT="$(abspath ${ROOT:-${mydir}/..})" BUILD_DIR="$(abspath "${BUILD_DIR:-${ROOT}/build}")" DEPS_DIR="${BUILD_DIR}/deps" export TAR_CMD="${TAR_CMD:-tar}" export TAR_OPTIONS="${TAR_OPTIONS:-}" export UNZIP_CMD="${UNZIP_CMD:-unzip}" export UNZIP_OPTIONS="${UNZIP_OPTIONS:--q} -u" export WGET="${WGET:-$(which wget)}" export WGET_OPTIONS="${WGET_OPTIONS:--q}" export CURL="${CURL:-$(which curl)}" export CURL_OPTIONS="${CURL_OPTIONS:--s -f -L}" export MAVEN_REPO_URL_BASE="${MAVEN_REPO_URL_BASE:-https://repo1.maven.org/maven2}" export CODE_TOOLS_URL_BASE="${CODE_TOOLS_URL_BASE:-https://git.openjdk.org}" export ANT_ARCHIVE_URL_BASE="${ANT_ARCHIVE_URL_BASE:-https://archive.apache.org/dist/ant/binaries}" setup_shasum ## # Support for Cygwin and MSYS2 (which may identify as MSYS, MINGW32 or MINGW64 (the default)) # case $(uname) in CYGWIN*|MSYS*|MINGW*) CYGWIN_OR_MSYS=1 ;; *) CYGWIN_OR_MSYS=0 ;; esac info "CYGWIN_OR_MSYS=$CYGWIN_OR_MSYS" jtreg-jtreg-7.4-1/make/build-support/jtharness/000077500000000000000000000000001461415321300214755ustar00rootroot00000000000000jtreg-jtreg-7.4-1/make/build-support/jtharness/build.sh000066400000000000000000000062441461415321300231360ustar00rootroot00000000000000#!/bin/bash # # 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. Oracle designates this # particular file as subject to the "Classpath" exception as provided # by Oracle in the LICENSE file that accompanied this code. # # 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. # mydir="$(dirname ${BASH_SOURCE[0]})" log_module="$(basename "${BASH_SOURCE[0]}")" . "${mydir}/../build-common.sh" . "${mydir}/version-numbers" JTHARNESS_SRC_TAG="${JTHARNESS_SRC_TAG:-${DEFAULT_JTHARNESS_SRC_TAG}}" JTHARNESS_SRC_ARCHIVE_CHECKSUM="${JTHARNESS_SRC_ARCHIVE_CHECKSUM:-${DEFAULT_JTHARNESS_SRC_ARCHIVE_CHECKSUM}}" ANT_VERSION="${ANT_VERSION:-${DEFAULT_ANT_VERSION}}" ANT_ARCHIVE_CHECKSUM="${ANT_ARCHIVE_CHECKSUM:-${DEFAULT_ANT_ARCHIVE_CHECKSUM}}" setup_ant info "ANT: ${ANT}" setup_jtharness_source() { check_arguments "${FUNCNAME}" 1 $# local dir="$1" # Build jtharness local JTHARNESS_LOCAL_SRC_ARCHIVE="${dir}/../source.zip" if [ "${JTHARNESS_SRC_TAG}" = "tip" -o "${JTHARNESS_SRC_TAG}" = "master" ]; then local BRANCH="master" get_archive_no_checksum "${CODE_TOOLS_URL_BASE}/jtharness/archive/${BRANCH}.zip" "${JTHARNESS_LOCAL_SRC_ARCHIVE}" "${dir}" JTHARNESS_SRC_DIR="${dir}/jtharness-${BRANCH}" else get_archive "${CODE_TOOLS_URL_BASE}/jtharness/archive/${JTHARNESS_SRC_TAG}.zip" "${JTHARNESS_LOCAL_SRC_ARCHIVE}" "${dir}" "${JTHARNESS_SRC_ARCHIVE_CHECKSUM}" JTHARNESS_SRC_DIR="${dir}/jtharness-${JTHARNESS_SRC_TAG}" fi } build_jtharness() { check_arguments "${FUNCNAME}" 0 $# local JTHARNESS_SRC_DIR_BASE="${BUILD_DIR}/src" setup_jtharness_source "${JTHARNESS_SRC_DIR_BASE}" local JTHARNESS_DIST="${BUILD_DIR}/build" "${ANT}" -DBUILD_DIR="$(native_path "${JTHARNESS_DIST}")" -f "$(native_path "${JTHARNESS_SRC_DIR}/build/build.xml")" JTHARNESS_JAVATEST_JAR="${JTHARNESS_DIST}/binaries/lib/javatest.jar" JTHARNESS_LICENSE="${JTHARNESS_SRC_DIR}/LICENSE" JTHARNESS_COPYRIGHT="${JTHARNESS_SRC_DIR}/legal/copyright.txt" } build_jtharness if [ ! x"$BUILD_RESULTS_FILE" = x"" ]; then mkdir -p "$(dirname "${BUILD_RESULTS_FILE}")" cat > "${BUILD_RESULTS_FILE}" << EOF JTHARNESS_JAVATEST_JAR="${JTHARNESS_JAVATEST_JAR}" JTHARNESS_LICENSE="${JTHARNESS_LICENSE}" JTHARNESS_COPYRIGHT="${JTHARNESS_COPYRIGHT}" EOF fi jtreg-jtreg-7.4-1/make/build-support/jtharness/version-numbers000066400000000000000000000025651461415321300245660ustar00rootroot00000000000000# # 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. Oracle designates this # particular file as subject to the "Classpath" exception as provided # by Oracle in the LICENSE file that accompanied this code. # # 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. # DEFAULT_JTHARNESS_SRC_TAG=jt6.0-b24 DEFAULT_JTHARNESS_SRC_ARCHIVE_CHECKSUM=3d25ddea8e59ab8ff0943bc65aebc80a2aecc4a3 DEFAULT_ANT_VERSION=1.10.8 DEFAULT_ANT_ARCHIVE_CHECKSUM=dbe187ce2963f9df8a67de8aaff3b0a437d06978 jtreg-jtreg-7.4-1/make/build-support/version-numbers000066400000000000000000000043071461415321300225610ustar00rootroot00000000000000# # 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. Oracle designates this # particular file as subject to the "Classpath" exception as provided # by Oracle in the LICENSE file that accompanied this code. # # 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. # JTREG_VERSION=7.4 DEFAULT_ANT_VERSION=1.10.8 DEFAULT_ANT_ARCHIVE_CHECKSUM=dbe187ce2963f9df8a67de8aaff3b0a437d06978 DEFAULT_ANT_JAR_CHECKSUM=ae148abb0532b685c5eeb22fdec9d124e89be5de DEFAULT_ASMTOOLS_SRC_TAG=7.0-b09 DEFAULT_ASMTOOLS_SRC_ARCHIVE_CHECKSUM=604f5e1aad1912968781dc72a1f86043e4e2dc20 DEFAULT_GOOGLE_GUICE_VERSION=5.1.0 DEFAULT_GOOGLE_GUICE_JAR_CHECKSUM=da25056c694c54ba16e78e4fc35f17fc60f0d1b4 DEFAULT_JCOMMANDER_VERSION=1.82 DEFAULT_JCOMMANDER_JAR_CHECKSUM=0a7c5fef184d238065de38f81bbc6ee50cca2e21 DEFAULT_JTHARNESS_SRC_TAG=jt6.0-b24 DEFAULT_JTHARNESS_SRC_ARCHIVE_CHECKSUM=3d25ddea8e59ab8ff0943bc65aebc80a2aecc4a3 # JUnit 5 = JUnit Platform 1.y.z + JUnit Jupiter 5.y.z + JUnit Vintage 5.y.z DEFAULT_JUNIT_VERSION=1.10.2 DEFAULT_JUNIT_JAR_CHECKSUM=552303cce67dc3485ded393d744c0f6b5cae355b DEFAULT_JUNIT_LICENSE_FILE=LICENSE-junit.txt DEFAULT_TESTNG_VERSION=7.3.0 DEFAULT_TESTNG_JAR_CHECKSUM=a5069c3dfba58d23702f96c3d9f5081f5ce7136f DEFAULT_TESTNG_LICENSE_VERSION=7.3.0 DEFAULT_TESTNG_LICENSE_CHECKSUM=c646d2cd1433560a4b43cb98e7273b59aac4563c jtreg-jtreg-7.4-1/make/build.sh000066400000000000000000000673061461415321300163320ustar00rootroot00000000000000#!/bin/bash # # 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 # under the terms of the GNU General Public License version 2 only, as # published by the Free Software Foundation. Oracle designates this # particular file as subject to the "Classpath" exception as provided # by Oracle in the LICENSE file that accompanied this code. # # 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. # # This script will download/build the dependencies for jtreg and then # build jtreg. Downloaded files are verified against known/specified # checksums. # The default version to use when building jtreg can be found in the # make/version-numbers file, where the default versions and # corresponding known checksums for the dependencies are also # specified. Almost all of the defaults can be overridden by setting # the respective environment variables. # For each of the dependency the following steps are applied and the # first successful one is used: # # 1. Check if the dependency is available locally # 2. Download a prebuilt version of the dependency # 3. Build the dependency from source, downloading the source archive # first # # In particular, when not found locally the dependencies will be # handled as follows: # # * JUnit, TestNG, JCommander, and Ant jar are by default # downloaded from Maven central. # * JT Harness and AsmTools are downloaded or built from source. # * The JDK dependency is downloaded. No default URL is set. # # Some noteworthy control variables: # # MAVEN_REPO_URL_BASE (e.g. "https://repo1.maven.org/maven2") # The base URL for the maven central repository. # # CODE_TOOLS_URL_BASE (e.g. "https://git.openjdk.org") # The base URL for the code tools source repositories. # # ANT_ARCHIVE_URL_BASE (e.g. "https://archive.apache.org/dist/ant/binaries") # The base URL for Ant dist binaries. # # JTREG_VERSION (e.g. "5.2") # JTREG_VERSION_STRING (e.g. "jtreg-5.2+8" # JTREG_BUILD_NUMBER (e.g. "8") # JTREG_BUILD_MILESTONE (e.g. "dev") # The version information to use for when building jtreg. # # MAKE_ARGS (e.g. "-j4 all") # Additional arguments to pass to make when building jtreg. # # WGET # The wget-like executable to use when downloading files. # # WGET_OPTS (e.g. "-v") # Additional arguments to pass to WGET when downloading files. # # CURL (e.g. "/path/to/my/wget") # The curl-like executable to use when downloading files. # Note: If available, wget will be preferred. # # CURL_OPTS (e.g. "-v") # Additional arguments to pass to CURL when downloading files. # # SKIP_DOWNLOAD # Skip the downloads if the file is already present locally. # # SKIP_CHECKSUM_CHECK # Skip the checksum verification for downloaded files. # The control variables for dependencies are on the following general # form (not all of them are relevant for all dependencies): # # _URL (e.g. JTHARNESS_ARCHIVE_URL) # The full URL for the dependency. # # _URL_BASE (e.g. JTHARNESS_ARCHIVE_URL_BASE) # The base URL for the dependency. Requires additional dependency # specific variables to be specified. # # _CHECKSUM (e.g. JTHARNESS_ARCHIVE_CHECKSUM) # The expected checksum of the download file. # # _SRC_TAG (e.g. JTHARNESS_SRC_TAG) # The SCM tag to use when building from source. The special value # "tip" can be used to get the most recent version. # # _SRC_ARCHIVE_CHECKSUM (e.g. JTHARNESS_SRC_ARCHIVE_CHECKSUM) # The checksum of the source archive. # # The below outlines the details of how the dependencies are # handled. For each dependency the steps are tried in order and the # first successful one will be used. # # Ant (required to build AsmTools and JT Harness) # Checksum variables: # ANT_ARCHIVE_CHECKSUM: checksum of binary archive # # 1. ANT # The path to the ant executable. # 2a. ANT_ARCHIVE_URL # The full URL for the archive. # 2b. ANT_ARCHIVE_URL_BASE + ANT_VERSION # The individual URL components used to construct the full URL. # # AsmTools # Checksum variables: # ASMTOOLS_ARCHIVE_CHECKSUM: checksum of binary archive # ASMTOOLS_SRC_ARCHIVE_CHECKSUM: checksum of source archive # # 1. ASMTOOLS_JAR + ASMTOOLS_LICENSE # The path to asmtools.jar and LICENSE respectively. # 2a. ASMTOOLS_ARCHIVE_URL # The full URL for the archive. # 2b. ASMTOOLS_ARCHIVE_URL_BASE + ASMTOOLS_VERSION + ASMTOOLS_BUILD_NUMBER + ASMTOOLS_FILE # The individual URL components used to construct the full URL. # 3. ASMTOOLS_SRC_TAG # The SCM repository tag to use when building from source. # # Google Guice (required by TestNG) # Checksum variables: # GOOGLE_GUICE_JAR_CHECKSUM: checksum of jar # # 1. GOOGLE_GUICE_JAR # The path to guice.jar. # 2a. GOOGLE_GUICE_JAR_URL # The full URL for the jar. # 2b. GOOGLE_GUICE_JAR_URL_BASE + GOOGLE_GUICE_VERSION # The individual URL components used to construct the full URL. # # JCommander (required by TestNG) # Checksum variables: # JCOMMANDER_JAR_CHECKSUM: checksum of jar # # 1. JCOMMANDER_JAR # The path to jcommander.jar. # 2a. JCOMMANDER_JAR_URL # The full URL for the jar. # 2b. JCOMMANDER_JAR_URL_BASE + JCOMMANDER_VERSION # The individual URL components used to construct the full URL. # # JDK # Checksum variables: # JDK_ARCHIVE_CHECKSUM: checksum of binary archive # # 1. JAVA_HOME # The path to the JDK. # 2a. JDK_ARCHIVE_URL # The full URL for the archive. # 2b. JDK_ARCHIVE_URL_BASE + JDK_VERSION + JDK_BUILD_NUMBER + JDK_FILE # The individual URL components used to construct the full URL. # # JT Harness # Checksum variables: # JTHARNESS_ARCHIVE_CHECKSUM: checksum of binary archive # JTHARNESS_SRC_ARCHIVE_CHECKSUM: checksum of source archive # # 1. JTHARNESS_JAVATEST_JAR + JTHARNESS_LICENSE + JTHARNESS_COPYRIGHT # The path to javatest.jar, LICENSE, and copyright.txt respectively. # 2a. JTHARNESS_ARCHIVE_URL # The full URL for the archive. # 2b. JTHARNESS_ARCHIVE_URL_BASE + JTHARNESS_VERSION + JTHARNESS_BUILD_NUMBER + JTHARNESS_FILE # The individual URL components used to construct the full URL. # 3. JTHARNESS_SRC_TAG # The SCM repository tag to use when building from source. # # JUnit (includes HamCrest) # Checksum variables: # JUNIT_JAR_CHECKSUM: checksum of binary archive # # 1. JUNIT_JAR + JUNIT_LICENSE # The path to junit.jar and LICENSE respectively. # 2a. JUNIT_JAR_URL # The full URL for the jar. # 2b. JUNIT_JAR_URL_BASE + JUNIT_VERSION + JUNIT_FILE # The individual URL components used to construct the full URL. # # TestNG (requires JCommander, Google Guice) # Checksum variables: # TESTNG_JAR_CHECKSUM: checksum of binary archive # TESTNG_LICENSE_CHECKSUM: checksum of LICENSE file # # 1. TESTNG_JAR + TESTNG_LICENSE # The path to testng.jar and LICENSE.txt respectively. # 2a. TESTNG_JAR_URL # The full URL for the jar. # 2b. TESTNG_JAR_URL_BASE + TESTNG_VERSION + TESTNG_FILE # The individual URL components used to construct the full URL. # mydir="$(dirname ${BASH_SOURCE[0]})" log_module="$(basename "${BASH_SOURCE[0]}")" . "${mydir}/build-support/build-common.sh" usage() { echo "Usage: $0 [ [--] ]" echo "--help" echo " Show this message" echo "--jdk /path/to/jdk" echo " Path to JDK; must be JDK 11 or higher" echo "--quiet | -q" echo " Reduce the logging output." echo "--show-default-versions" echo " Show default versions of external components" echo "--show-config-details" echo " Show configuration details" echo "--skip-checksum-check" echo " Skip the checksum check for downloaded files." echo "--skip-download" echo " Skip downloading files if file already available" echo "--skip-make" echo " Skip running 'make' (just download dependencies if needed)" echo "--version-numbers file" echo " Provide an alternate file containing dependency version information" echo "--" echo " Subsequent arguments are for 'make'" } ensure_arg() { check_arguments "${FUNCNAME}" 2 $# local option="$1" local arg_count="$2" if [ "$2" -lt "2" ]; then echo "The $option option requires an argument" exit fi } process_args() { while [ "$#" -gt 0 ]; do case "$1" in --help|-h ) HELP=1 ; shift ;; --jdk ) ensure_arg "$1" $# ; JAVA_HOME="$2" ; shift ; shift ;; --quiet|-q ) export QUIET=1 ; shift ;; --show-config-details ) SHOW_CONFIG_DETAILS=1 ; shift ;; --show-default-versions ) SHOW_DEFAULT_VERSIONS=1 ; shift ;; --skip-checksum-check ) export SKIP_CHECKSUM_CHECK=1 ; shift ;; --skip-download ) export SKIP_DOWNLOAD=1 ; shift ;; --skip-make ) SKIP_MAKE=1 ; shift ;; --version-numbers ) ensure_arg "$1" $# ; VERSION_NUMBERS="$2" ; shift ; shift ;; -- ) shift ; MAKE_ARGS="$@" ; break ;; -* ) error "unknown option: '$1'" ; exit 1 ;; * ) MAKE_ARGS="$@" ; break ;; esac done } process_args "$@" if [ -n "${HELP:-}" ]; then usage exit fi . "${VERSION_NUMBERS:-${mydir}/build-support/version-numbers}" JTREG_VERSION="${JTREG_VERSION:-}" ANT_VERSION="${ANT_VERSION:-${DEFAULT_ANT_VERSION}}" ANT_ARCHIVE_CHECKSUM="${ANT_ARCHIVE_CHECKSUM:-${DEFAULT_ANT_ARCHIVE_CHECKSUM}}" # Not available in Maven ASMTOOLS_SRC_TAG="${ASMTOOLS_SRC_TAG:-${DEFAULT_ASMTOOLS_SRC_TAG}}" ASMTOOLS_SRC_ARCHIVE_CHECKSUM="${ASMTOOLS_SRC_ARCHIVE_CHECKSUM:-${DEFAULT_ASMTOOLS_SRC_ARCHIVE_CHECKSUM}}" GOOGLE_GUICE_VERSION="${GOOGLE_GUICE_VERSION:-${DEFAULT_GOOGLE_GUICE_VERSION}}" GOOGLE_GUICE_JAR_URL_BASE="${GOOGLE_GUICE_JAR_URL_BASE:-${MAVEN_REPO_URL_BASE}}" GOOGLE_GUICE_JAR_CHECKSUM="${GOOGLE_GUICE_JAR_CHECKSUM:-${DEFAULT_GOOGLE_GUICE_JAR_CHECKSUM}}" JCOMMANDER_VERSION="${JCOMMANDER_VERSION:-${DEFAULT_JCOMMANDER_VERSION}}" JCOMMANDER_JAR_URL_BASE="${JCOMMANDER_JAR_URL_BASE:-${MAVEN_REPO_URL_BASE}}" JCOMMANDER_JAR_CHECKSUM="${JCOMMANDER_JAR_CHECKSUM:-${DEFAULT_JCOMMANDER_JAR_CHECKSUM}}" # Not available in Maven JTHARNESS_SRC_TAG="${JTHARNESS_SRC_TAG:-${DEFAULT_JTHARNESS_SRC_TAG}}" JTHARNESS_SRC_ARCHIVE_CHECKSUM="${JTHARNESS_SRC_ARCHIVE_CHECKSUM:-${DEFAULT_JTHARNESS_SRC_ARCHIVE_CHECKSUM}}" JUNIT_VERSION="${JUNIT_VERSION:-${DEFAULT_JUNIT_VERSION}}" JUNIT_JAR_URL_BASE="${JUNIT_JAR_URL_BASE:-${MAVEN_REPO_URL_BASE}}" JUNIT_JAR_CHECKSUM="${JUNIT_JAR_CHECKSUM:-${DEFAULT_JUNIT_JAR_CHECKSUM}}" JUNIT_LICENSE_FILE="${JUNIT_LICENSE_FILE:-${DEFAULT_JUNIT_LICENSE_FILE}}" TESTNG_VERSION="${TESTNG_VERSION:-${DEFAULT_TESTNG_VERSION}}" TESTNG_JAR_URL_BASE="${TESTNG_JAR_URL_BASE:-${MAVEN_REPO_URL_BASE}}" TESTNG_JAR_CHECKSUM="${TESTNG_JAR_CHECKSUM:-${DEFAULT_TESTNG_JAR_CHECKSUM}}" TESTNG_LICENSE_VERSION="${TESTNG_LICENSE_VERSION:-${DEFAULT_TESTNG_LICENSE_VERSION:-${TESTNG_VERSION}}}" TESTNG_LICENSE_CHECKSUM="${TESTNG_LICENSE_CHECKSUM:-${DEFAULT_TESTNG_LICENSE_CHECKSUM}}" if [ "${SHOW_DEFAULT_VERSIONS:-}" != "" ]; then find ${mydir} -name version-numbers | \ xargs cat | \ grep -v '^#' | \ grep -E 'DEFAULT.*(_VERSION|_SRC_TAG)' | \ sort -u exit fi if [ "${SHOW_CONFIG_DETAILS:-}" != "" ]; then ( set -o posix ; set ) | \ grep -E '^(ANT|ASM|ASMTOOLS|GOOGLE_GUICE|JCOMMANDER|JTHARNESS|JUNIT|TESTNG)_[A-Z_]*=' | \ sort -u exit fi setup_java_home() { check_arguments "${FUNCNAME}" 0 $# if [ -n "${JAVA_HOME:-}" ]; then return fi if [ -z "${JDK_ARCHIVE_URL:-}" ]; then if [ -n "${JDK_ARCHIVE_URL_BASE:-}" ]; then if [ -z "${JDK_VERSION:-}" ]; then error "JDK_VERSION not set" exit 1 fi if [ -z "${JDK_BUILD_NUMBER:-}" ]; then error "JDK_BUILD_NUMBER not set" exit 1 fi if [ -z "${JDK_FILE:-}" ]; then error "JDK_FILE not set" exit 1 fi JDK_ARCHIVE_URL="${JDK_ARCHIVE_URL_BASE}/${JDK_VERSION}/${JDK_BUILD_NUMBER}/${JDK_FILE}" fi fi local JDK_DEPS_DIR="${DEPS_DIR}" if [ -n "${JDK_ARCHIVE_URL:-}" ]; then local JDK_LOCAL_ARCHIVE_FILE="${DEPS_DIR}/$(basename "${JDK_ARCHIVE_URL}")" if [ -n "${JDK_ARCHIVE_CHECKSUM:-}" ]; then get_archive "${JDK_ARCHIVE_URL}" "${JDK_LOCAL_ARCHIVE_FILE}" "${JDK_DEPS_DIR}" "${JDK_ARCHIVE_CHECKSUM}" else get_archive_no_checksum "${JDK_ARCHIVE_URL}" "${JDK_LOCAL_ARCHIVE_FILE}" "${JDK_DEPS_DIR}" fi local JDK_JAVAC="$(find "${JDK_DEPS_DIR}" -path '*/bin/javac')" JAVA_HOME="$(dirname $(dirname "${JDK_JAVAC}"))" return fi error "None of JAVA_HOME, JDK_ARCHIVE_URL or JDK_ARCHIVE_URL_BASE are set" exit 1 } sanity_check_java_home() { if [ -z "${JAVA_HOME:-}" ]; then error "No JAVA_HOME set" exit 1 fi if [ ! -d "${JAVA_HOME}" ]; then error "'${JAVA_HOME}' is not a directory" exit 1 fi if [ ! -x "${JAVA_HOME}/bin/java" ]; then error "Could not find an executable binary at '${JAVA_HOME}/bin/java'" exit 1 fi local version=$(${JAVA_HOME}/bin/java -version 2>&1) local vnum=$(echo "${version}" | \ grep -e ^java -e ^openjdk | head -n 1 | \ sed -e 's/^[^0-9]*\(1\.\)*\([1-9][0-9]*\).*/\2/' ) if [ "${vnum:-0}" -lt "11" ]; then error "JDK 11 or newer is required to build jtreg" exit 1 fi } checkJavaOSVersion() { # This checks that the value in the Java "os.version" system property # is as expected. While it is OK to *build* jtreg with a JDK with this bug, # some of the `jtreg` self-tests will fail: notably, test/problemList. # See https://bugs.openjdk.org/browse/JDK-8253702 case `uname` in Darwin ) OS_VERSION=`defaults read loginwindow SystemVersionStampAsString` ${JAVA_HOME}/bin/java ${mydir}/CheckJavaOSVersion.java ${OS_VERSION} esac } setup_java_home sanity_check_java_home #checkJavaOSVersion #temp: check for presence of the JDK os.version bug (JDK-8253702) export JAVA_HOME info "JAVA_HOME: ${JAVA_HOME}" #----- Ant ----- setup_ant info "ANT: ${ANT}" #----- JT Harness ----- setup_jtharness_javatest_jar() { check_arguments "${FUNCNAME}" 0 $# if [ -n "${JTHARNESS_JAVATEST_JAR:-}" ]; then return fi if [ -z "${JTHARNESS_ARCHIVE_URL:-}" ]; then if [ -n "${JTHARNESS_ARCHIVE_URL_BASE:-}" ]; then JTHARNESS_ARCHIVE_URL="${JTHARNESS_ARCHIVE_URL_BASE}/${JTHARNESS_VERSION}/${JTHARNESS_BUILD_NUMBER}/${JTHARNESS_FILE}" fi fi local JTHARNESS_DEPS_DIR="${DEPS_DIR}/jtharness" if [ -n "${JTHARNESS_ARCHIVE_URL:-}" ]; then local JTHARNESS_LOCAL_ARCHIVE_FILE="${DEPS_DIR}/$(basename "${JTHARNESS_ARCHIVE_URL}")" get_archive "${JTHARNESS_ARCHIVE_URL}" "${JTHARNESS_LOCAL_ARCHIVE_FILE}" "${JTHARNESS_DEPS_DIR}" "${JTHARNESS_ARCHIVE_CHECKSUM}" JTHARNESS_JAVATEST_JAR="$(find "${JTHARNESS_DEPS_DIR}" -path '*/lib/javatest.jar')" JTHARNESS_LICENSE="$(dirname "${JTHARNESS_JAVATEST_JAR}")/../LICENSE" JTHARNESS_COPYRIGHT="$(dirname "${JTHARNESS_JAVATEST_JAR}")/../legal/copyright.txt" return fi info "None of JTHARNESS_JAVATEST_JAR, JTHARNESS_ARCHIVE_URL or JTHARNESS_ARCHIVE_URL_BASE are set; building from source" export JTHARNESS_BUILD_RESULTS_FILE="${DEPS_DIR}/jtharness.results" ( export BUILD_DIR="${JTHARNESS_DEPS_DIR}" export BUILD_RESULTS_FILE="${JTHARNESS_BUILD_RESULTS_FILE}" export JTHARNESS_SRC_TAG="${JTHARNESS_SRC_TAG}" export JTHARNESS_SRC_ARCHIVE_CHECKSUM="${JTHARNESS_SRC_ARCHIVE_CHECKSUM}" export ANT="${ANT}" bash "${mydir}/build-support/jtharness/build.sh" ) ret=$? if [ ! $ret = 0 ]; then exit ${ret} fi . "${JTHARNESS_BUILD_RESULTS_FILE}" } setup_jtharness_javatest_jar info "JTHARNESS_JAVATEST_JAR: ${JTHARNESS_JAVATEST_JAR}" #----- JT Harness License and Copyright ----- setup_jtharness_license_and_copyright() { check_arguments "${FUNCNAME}" 0 $# if [ -n "${JTHARNESS_LICENSE:-}" -a -n "${JTHARNESS_COPYRIGHT:-}" ]; then return fi if [ -z "${JTHARNESS_SRC:-}" ]; then local JTHARNESS_SRC_DEPS_DIR="${DEPS_DIR}/jtharness-src" local JTHARNESS_LOCAL_SRC_ARCHIVE="${JTHARNESS_SRC_DEPS_DIR}/source.zip" get_archive "${CODE_TOOLS_URL_BASE}/jtharness/archive/${JTHARNESS_SRC_VERSION}.zip" "${JTHARNESS_LOCAL_SRC_ARCHIVE}" "${JTHARNESS_SRC_DEPS_DIR}" "${JTHARNESS_SRC_ARCHIVE_CHECKSUM}" JTHARNESS_SRC="${JTHARNESS_SRC_DEPS_DIR}/jtharness-${JTHARNESS_SRC_VERSION}" fi JTHARNESS_LICENSE="${JTHARNESS_SRC}/LICENSE" JTHARNESS_COPYRIGHT="${JTHARNESS_SRC}/legal/copyright.txt" } setup_jtharness_license_and_copyright info "JTHARNESS_LICENSE: ${JTHARNESS_LICENSE}" info "JTHARNESS_COPYRIGHT: ${JTHARNESS_COPYRIGHT}" #----- AsmTools ----- setup_asmtools() { check_arguments "${FUNCNAME}" 0 $# if [ -n "${ASMTOOLS_JAR:-}" -a -n "${ASMTOOLS_LICENSE:-}" ]; then return fi if [ -z "${ASMTOOLS_ARCHIVE_URL:-}" ]; then if [ -n "${ASMTOOLS_ARCHIVE_URL_BASE:-}" ]; then if [ -z "${ASMTOOLS_VERSION:-}" ]; then error "ASMTOOLS_VERSION not set" exit 1 fi if [ -z "${ASMTOOLS_BUILD_NUMBER:-}" ]; then error "ASMTOOLS_BUILD_NUMBER not set" exit 1 fi if [ -z "${ASMTOOLS_FILE:-}" ]; then error "ASMTOOLS_FILE not set" exit 1 fi ASMTOOLS_ARCHIVE_URL="${ASMTOOLS_ARCHIVE_URL_BASE}/${ASMTOOLS_VERSION}/${ASMTOOLS_BUILD_NUMBER}/${ASMTOOLS_FILE}" fi fi local ASMTOOLS_DEPS_DIR="${DEPS_DIR}/asmtools" if [ -n "${ASMTOOLS_ARCHIVE_URL:-}" ]; then local ASMTOOLS_LOCAL_ARCHIVE_FILE="${DEPS_DIR}/$(basename "${ASMTOOLS_ARCHIVE_URL}")" get_archive "${ASMTOOLS_ARCHIVE_URL}" "${ASMTOOLS_LOCAL_ARCHIVE_FILE}" "${ASMTOOLS_DEPS_DIR}" "${ASMTOOLS_ARCHIVE_CHECKSUM}" ASMTOOLS_JAR="$(find "${ASMTOOLS_DEPS_DIR}" -name asmtools.jar)" ASMTOOLS_LICENSE="$(dirname "${ASMTOOLS_JAR}")/../LICENSE" return fi info "None of ASMTOOLS_JAR, ASMTOOLS_ARCHIVE_URL or ASMTOOLS_ARCHIVE_URL_BASE are set; building from source" export ASMTOOLS_BUILD_RESULTS_FILE="${DEPS_DIR}/asmtools.results" ( export BUILD_DIR="${ASMTOOLS_DEPS_DIR}" export BUILD_RESULTS_FILE="${ASMTOOLS_BUILD_RESULTS_FILE}" export ANT="${ANT}" export ASMTOOLS_SRC_TAG="${ASMTOOLS_SRC_TAG}" bash "${mydir}/build-support/asmtools/build.sh" ) ret=$? if [ ! $ret = 0 ]; then exit ${ret} fi . "${ASMTOOLS_BUILD_RESULTS_FILE}" } setup_asmtools info "ASMTOOLS_JAR: ${ASMTOOLS_JAR}" info "ASMTOOLS_LICENSE: ${ASMTOOLS_LICENSE}" #----- JUnit ----- setup_junit() { check_arguments "${FUNCNAME}" 0 $# if [ -n "${JUNIT_JAR:-}" ]; then return fi if [ -z "${JUNIT_JAR_URL:-}" ]; then if [ -n "${JUNIT_JAR_URL_BASE:-}" ]; then JUNIT_JAR_URL="${JUNIT_JAR_URL_BASE}/org/junit/platform/junit-platform-console-standalone/${JUNIT_VERSION}/junit-platform-console-standalone-${JUNIT_VERSION}.jar" fi fi local JUNIT_DEPS_DIR="${DEPS_DIR}/junit" if [ -n "${JUNIT_JAR_URL:-}" ]; then JUNIT_JAR="${JUNIT_DEPS_DIR}/$(basename ${JUNIT_JAR_URL})" download_and_checksum "${JUNIT_JAR_URL}" "${JUNIT_JAR}" "${JUNIT_JAR_CHECKSUM}" return fi error "None of JUNIT_JAR, JUNIT_JAR_URL or JUNIT_JAR_URL_BASE is set" exit 1 } setup_junit info "JUNIT_JAR ${JUNIT_JAR}" #----- JUnit license ----- setup_junit_license() { check_arguments "${FUNCNAME}" 0 $# if [ -n "${JUNIT_LICENSE:-}" ]; then return fi local JUNIT_LICENSE_DEPS_DIR="${DEPS_DIR}/junit-license" "${UNZIP_CMD}" ${UNZIP_OPTIONS} "${JUNIT_JAR}" ${JUNIT_LICENSE_FILE} -d "${JUNIT_LICENSE_DEPS_DIR}" JUNIT_LICENSE="${JUNIT_LICENSE_DEPS_DIR}/${JUNIT_LICENSE_FILE}" } setup_junit_license info "JUNIT_LICENSE: ${JUNIT_LICENSE}" #----- TestNG ----- setup_testng() { check_arguments "${FUNCNAME}" 0 $# if [ -n "${TESTNG_JAR:-}" ]; then return fi if [ -z "${TESTNG_JAR_URL:-}" ]; then if [ -n "${TESTNG_JAR_URL_BASE:-}" ]; then TESTNG_JAR_URL="${TESTNG_JAR_URL_BASE}/org/testng/testng/${TESTNG_VERSION}/testng-${TESTNG_VERSION}.jar" fi fi local TESTNG_DEPS_DIR="${DEPS_DIR}/testng" if [ -n "${TESTNG_JAR_URL:-}" ]; then TESTNG_JAR="${TESTNG_DEPS_DIR}/$(basename "${TESTNG_JAR_URL}")" download_and_checksum "${TESTNG_JAR_URL}" "${TESTNG_JAR}" "${TESTNG_JAR_CHECKSUM}" return fi error "None of TESTNG_JAR, TESTNG_JAR_URL or TESTNG_JAR_URL_BASE are set" exit 1 } setup_testng info "TESTNG_JAR: ${TESTNG_JAR}" #----- TestNG License ----- setup_testng_license() { check_arguments "${FUNCNAME}" 0 $# if [ -n "${TESTNG_LICENSE:-}" ]; then return fi local TESTNG_LICENSE_DEPS_DIR="${DEPS_DIR}/testng-license" TESTNG_LICENSE="${TESTNG_LICENSE_DEPS_DIR}/LICENSE.txt" download_and_checksum "https://raw.githubusercontent.com/cbeust/testng/${TESTNG_LICENSE_VERSION}/LICENSE.txt" "${TESTNG_LICENSE}" "${TESTNG_LICENSE_CHECKSUM}" } setup_testng_license info "TESTNG_LICENSE: ${TESTNG_LICENSE}" #----- JCommander (required by TestNG) ----- setup_jcommander() { check_arguments "${FUNCNAME}" 0 $# if [ -n "${JCOMMANDER_JAR:-}" ]; then return fi if [ -z "${JCOMMANDER_JAR_URL:-}" ]; then if [ -n "${JCOMMANDER_JAR_URL_BASE:-}" ]; then JCOMMANDER_JAR_URL="${JCOMMANDER_JAR_URL_BASE}/com/beust/jcommander/${JCOMMANDER_VERSION}/jcommander-${JCOMMANDER_VERSION}.jar" fi fi local JCOMMANDER_DEPS_DIR="${DEPS_DIR}/jcommander" if [ -n "${JCOMMANDER_JAR_URL:-}" ]; then JCOMMANDER_JAR="${JCOMMANDER_DEPS_DIR}/$(basename "${JCOMMANDER_JAR_URL}")" download_and_checksum "${JCOMMANDER_JAR_URL}" "${JCOMMANDER_JAR}" "${JCOMMANDER_JAR_CHECKSUM}" return fi error "None of JCOMMANDER_JAR, JCOMMANDER_JAR_URL or JCOMMANDER_JAR_URL_BASE are set" exit 1 } setup_jcommander info "JCOMMANDER_JAR: ${JCOMMANDER_JAR}" #----- Google Guice (required by TestNG) ----- setup_google_guice() { check_arguments "${FUNCNAME}" 0 $# if [ -n "${GOOGLE_GUICE_JAR:-}" ]; then return fi if [ -z "${GOOGLE_GUICE_JAR_URL:-}" ]; then if [ -n "${GOOGLE_GUICE_JAR_URL_BASE:-}" ]; then GOOGLE_GUICE_JAR_URL="${GOOGLE_GUICE_JAR_URL_BASE}/com/google/inject/guice/${GOOGLE_GUICE_VERSION}/guice-${GOOGLE_GUICE_VERSION}.jar" fi fi local GOOGLE_GUICE_DEPS_DIR="${DEPS_DIR}/guice" if [ -n "${GOOGLE_GUICE_JAR_URL:-}" ]; then GOOGLE_GUICE_JAR="${GOOGLE_GUICE_DEPS_DIR}/$(basename "${GOOGLE_GUICE_JAR_URL}")" download_and_checksum "${GOOGLE_GUICE_JAR_URL}" "${GOOGLE_GUICE_JAR}" "${GOOGLE_GUICE_JAR_CHECKSUM}" return fi error "None of GOOGLE_GUICE_JAR, GOOGLE_GUICE_JAR_URL or GOOGLE_GUICE_JAR_URL_BASE are set" exit 1 } setup_google_guice info "GOOGLE_GUICE_JAR: ${GOOGLE_GUICE_JAR}" #----- # Create aggregate settings ASMTOOLS_NOTICES="$(mixed_path "${ASMTOOLS_LICENSE}")" info "ASMTOOLS_NOTICES: ${ASMTOOLS_NOTICES}" JTHARNESS_NOTICES="$(mixed_path "${JTHARNESS_COPYRIGHT}") $(mixed_path "${JTHARNESS_LICENSE}")" info "JTHARNESS_NOTICES: ${JTHARNESS_NOTICES}" TESTNG_JARS="$(mixed_path "${TESTNG_JAR}") $(mixed_path "${GOOGLE_GUICE_JAR}") $(mixed_path "${JCOMMANDER_JAR}")" info "TESTNG_JARS: ${TESTNG_JARS}" TESTNG_NOTICES="$(mixed_path "${TESTNG_LICENSE}")" info "TESTNG_NOTICES: ${TESTNG_NOTICES}" JUNIT_JARS="$(mixed_path "${JUNIT_JAR}")" info "JUNIT_JARS: ${JUNIT_JARS}" JUNIT_NOTICES="$(mixed_path "${JUNIT_LICENSE}")" info "JUNIT_NOTICES: ${JUNIT_NOTICES}" ## # The build version typically comes from the version-numbers file; # It is expected that the build number will typically come from an external CI system. # setup_build_info() { check_arguments "${FUNCNAME}" 0 $# JTREG_BUILD_MILESTONE="${JTREG_BUILD_MILESTONE:-dev}" JTREG_BUILD_NUMBER="${JTREG_BUILD_NUMBER:-0}" if [ -z "${JTREG_VERSION_STRING:-}" ]; then MILESTONE="" if [ -n "${JTREG_BUILD_MILESTONE}" ]; then MILESTONE="-${JTREG_BUILD_MILESTONE}" fi JTREG_VERSION_STRING="${JTREG_VERSION}${MILESTONE}+${JTREG_BUILD_NUMBER}" fi } setup_build_info info "JTREG_VERSION: ${JTREG_VERSION}" info "JTREG_BUILD_NUMBER: ${JTREG_BUILD_NUMBER}" info "JTREG_BUILD_MILESTONE: ${JTREG_BUILD_MILESTONE}" check_files() { for i in "$@" ; do check_file "$i" done } check_file() { check_arguments "${FUNCNAME}" 1 $# info "Checking $1" if [ ! -f "$1" ]; then error "Missing: $1" exit 1 fi } check_dir() { check_arguments "${FUNCNAME}" 1 $# info "Checking $1" if [ ! -d "$1" ]; then error "Missing: $1" exit 1 fi } check_file "${ANT}" check_file "${ASMTOOLS_JAR}" check_files ${ASMTOOLS_NOTICES} check_dir "${JAVA_HOME}" check_file "${JTHARNESS_JAVATEST_JAR}" check_files ${JTHARNESS_NOTICES} check_files ${JUNIT_JARS} check_files ${JUNIT_NOTICES} check_files ${TESTNG_JARS} check_files ${TESTNG_NOTICES} if [ -n "${SKIP_MAKE:-}" ]; then exit fi # save make command for possible later reuse, bypassing this script mkdir -p ${BUILD_DIR} cat > ${BUILD_DIR}/make.sh << EOF #!/bin/sh cd "${ROOT}/make" make ASMTOOLS_JAR="${ASMTOOLS_JAR}" \\ ASMTOOLS_NOTICES="${ASMTOOLS_NOTICES}" \\ BUILDDIR="${BUILD_DIR}" \\ BUILD_MILESTONE="${JTREG_BUILD_MILESTONE}" \\ BUILD_NUMBER="${JTREG_BUILD_NUMBER}" \\ BUILD_VERSION="${JTREG_VERSION}" \\ BUILD_VERSION_STRING="${JTREG_VERSION_STRING}" \\ JAVATEST_JAR="$(mixed_path "${JTHARNESS_JAVATEST_JAR}")" \\ JDKHOME="$(mixed_path ${JAVA_HOME})" \\ JTHARNESS_NOTICES="${JTHARNESS_NOTICES}" \\ JTREG_HOME="" \\ JT_HOME="" \\ JUNIT_JARS="${JUNIT_JARS}" \\ JUNIT_NOTICES="${JUNIT_NOTICES}" \\ TESTNG_JARS="${TESTNG_JARS}" \\ TESTNG_NOTICES="${TESTNG_NOTICES}" \\ "\$@" EOF sh ${BUILD_DIR}/make.sh ${MAKE_ARGS:-} jtreg-jtreg-7.4-1/make/i18n.pat000066400000000000000000000024601461415321300161520ustar00rootroot00000000000000# Patterns for recognizing i18n strings in source code # Each line is of the form # regexp keys # If the regexp matches within a line of source text, the keys give the # names of the implied i18n keys. Use the standard \int syntax for referring # to capture groups within the regexp. Note the regular expression should # not contain space characters. If necessary, use \s to match space. # For spec of regular expressions, see java.util.regex.Pattern # See also com.sun.jct.utils.i18ncheck.Main # i18n.getString("...", (printMessage|getI18NString|writeI18N|i18n.getString|formatI18N|setI18NTitle)\("([^"]*)"(,|\)) \2 # new BadArgs(i18n, "...", (Message.get|Fault|BadArgs|BadValue|println|printErrorMessage|printMessage|[eE]rror|showMessage|popupError|write|JavaTestError|\.log|super)\((msgs|i18n),\s"([^"]*)"(,|\)) \3 # uif.createMessageArea("...", uif.createMessageArea\("([^"]*)"(,|\)) \1.txt # uif.showXXYZDialog("...", uif.show(YesNo|YesNoCancel|OKCancel|Information|CustomInfo)Dialog\("([^"]*)"(,|\)) \2.txt \2.title # uif.showWaitDialog("...", uif.createWaitDialog\("([^"]*)"(,|\)) \1.txt \1.title \1.desc \1.name # showError("...", showError\("([^"]*)"(,|\)) \1.err # new FileType() new\sFileType\(\) filetype.allFiles # new FileType("...") new\sFileType\("([^"]*)"\) filetype\1 # i18n: ... i18n:\s*(\S+) \1 jtreg-jtreg-7.4-1/make/jtreg.gmk000066400000000000000000000306071461415321300165040ustar00rootroot00000000000000# # Copyright (c) 1999, 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. Oracle designates this # particular file as subject to the "Classpath" exception as provided # by Oracle in the LICENSE file that accompanied this code. # # 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. # #---------------------------------------------------------------------- # # compile com.sun.javatest.regtest DEFAULT_DEBUG_FLAGS = -g AGENT_DEBUG_FLAGS = $(DEFAULT_DEBUG_FLAGS) TOOL_DEBUG_FLAGS = $(DEFAULT_DEBUG_FLAGS) JAVA_LANG_DEBUG_FLAGS = $(DEFAULT_DEBUG_FLAGS) ### The following files are required to run agentvm and othervm tests, as far back as JDK 8 JUNIT_CLASSPATH = $(call AS_CLASSPATH,$(JUNIT_JARS)) TESTNG_CLASSPATH = $(call AS_CLASSPATH,$(TESTNG_JARS)) JAVAFILES.com.sun.javatest.regtest-agentvm := \ $(shell $(FIND) $(JAVADIR)/com/sun/javatest/regtest/agent -name \*.java ) $(BUILDDIR)/classes.com.sun.javatest.regtest.agent.ok: \ $(JAVAFILES.com.sun.javatest.regtest-agentvm) $(MKDIR) -p $(CLASSDIR) CLASSPATH="$(CLASSDIR)$(PS)$(JAVATEST_JAR)$(PS)$(JUNIT_CLASSPATH)$(PS)$(TESTNG_CLASSPATH)" \ $(REGTEST_AGENT_JAVAC) $(REGTEST_AGENT_JAVAC_OPTIONS) \ -d $(CLASSDIR) \ -encoding ASCII \ $(AGENT_DEBUG_FLAGS) \ $(JAVAFILES.com.sun.javatest.regtest-agentvm) echo "classes built at `date`" > $@ ### The following files are for the jtreg tool JAVAFILES.com.sun.javatest.regtest-tools := \ $(shell $(FIND) $(JAVADIR)/com/sun/javatest/regtest -name agent -prune -o -name \*.java -print ) $(BUILDDIR)/classes.com.sun.javatest.regtest.ok: \ $(JAVAFILES.com.sun.javatest.regtest-tools) \ $(BUILDDIR)/classes.com.sun.javatest.regtest.agent.ok CLASSPATH="$(CLASSDIR)$(PS)$(JAVATEST_JAR)$(PS)$(JUNIT_CLASSPATH)$(PS)$(TESTNG_CLASSPATH)" \ $(REGTEST_TOOL_JAVAC) $(REGTEST_TOOL_JAVAC_OPTIONS) \ -d $(CLASSDIR) \ -encoding ASCII \ $(TOOL_DEBUG_FLAGS) \ $(JAVAFILES.com.sun.javatest.regtest-tools) echo "classes built at `date`" > $@ TARGETS.com.sun.javatest.regtest += $(BUILDDIR)/classes.com.sun.javatest.regtest.ok JAVAFILES.java.lang := \ $(JAVADIR)/java/lang/JTRegModuleHelper.java # The hardcoded use of --release 9 reflects the introduction of the Java Platform Module System $(BUILDDIR)/classes.java.lang.ok: \ $(JAVAFILES.java.lang) CLASSPATH= \ $(REGTEST_TOOL_JAVAC) $(REGTEST_TOOL_JAVAC_OPTIONS) --release 9 $(REGTEST_TOOL_PATCH_JAVA_BASE_OPTIONS) \ -d $(CLASSDIR) \ -encoding ASCII \ $(JAVA_LANG_DEBUG_FLAGS) \ $(JAVAFILES.java.lang) echo "classes built at `date`" > $@ TARGETS.com.sun.javatest.regtest += $(BUILDDIR)/classes.java.lang.ok #---------------------------------------------------------------------- # # resources required for com.sun.javatest.regtest RESOURCES.com.sun.javatest.regtest = \ $(CLASSDIR)/META-INF/services/java.util.spi.ToolProvider \ $(CLASSDIR)/com/sun/javatest/regtest/config/i18n.properties \ $(CLASSDIR)/com/sun/javatest/regtest/report/i18n.properties \ $(CLASSDIR)/com/sun/javatest/regtest/tool/i18n.properties \ $(CLASSDIR)/com/sun/javatest/regtest/tool/jtlogo.png \ $(CLASSDIR)/com/sun/javatest/regtest/tool/jars.properties $(BUILDDIR)/classes/com/sun/javatest/regtest/tool/jars.properties: \ $(ASMTOOLS_JAR) \ $(TESTNG_JARS) \ $(JUNIT_JARS) $(MKDIR) -p $(@D) ( \ echo "asmtools=$(notdir $(ASMTOOLS_JAR))" ; \ echo "testng=$(notdir $(TESTNG_JARS))" ; \ echo "junit=$(notdir $(JUNIT_JARS))" \ ) > $@ TARGETS.com.sun.javatest.regtest += $(RESOURCES.com.sun.javatest.regtest) #---------------------------------------------------------------------- # # Misc. doc files JTREG_COPYRIGHT = $(JTREG_IMAGEDIR)/COPYRIGHT JTREG_LICENSE = $(JTREG_IMAGEDIR)/LICENSE JTREG_README = $(JTREG_IMAGEDIR)/README JTREG_FAQ = $(JTREG_IMAGEDIR)/doc/jtreg/faq.html JTREG_TAGSPEC = $(JTREG_IMAGEDIR)/doc/jtreg/tag-spec.html JTREG_USAGE = $(JTREG_IMAGEDIR)/doc/jtreg/usage.txt JTREG_DOCS = \ $(JTREG_COPYRIGHT) \ $(JTREG_FAQ) \ $(JTREG_LICENSE) \ $(JTREG_README) \ $(JTREG_TAGSPEC) \ $(JTREG_USAGE) $(JTREG_COPYRIGHT): $(TOPDIR)/COPYRIGHT $(MKDIR) -p $(@D) $(RM) $@ $(CP) $< $@ $(JTREG_FAQ): FAQ_PANDOC_OPTIONS = --to html5 $(BUILDDIR)/alt-faq.html: FAQ_PANDOC_OPTIONS = --to html4 --ascii $(BUILDDIR)/alt-faq.html: FAQ_SED_OPTIONS = -e '/max-width: 36em;/d' $(JTREG_FAQ) $(BUILDDIR)/alt-faq.html: $(SRCJTREGDOCDIR)/faq.md \ $(SRCJTREGDOCDIR)/faq-local-style.html \ $(SRCJTREGDOCDIR)/faq-intro.html $(MKDIR) -p $(@D) $(ECHO) '/
/{;:a;N;/<\/header>/!ba;};/

/d' | tr ';' '\n' > $(BUILDDIR)/fixupheader $(PANDOC) \ --standalone \ --include-in-header $(SRCJTREGDOCDIR)/faq-local-style.html \ --include-before $(SRCJTREGDOCDIR)/faq-intro.html \ --toc \ $(FAQ_PANDOC_OPTIONS) \ --number-sections \ $(SRCJTREGDOCDIR)/faq.md | \ $(SED) \ -e 's/^code > span\.\([a-z][a-z] .*\)/code span.\1/' \ -e 's/-section-number">0./-section-number">/' \ -e 's/…/\…/g' \ -e 's/â„¢/\™/g' \ -f $(BUILDDIR)/fixupheader \ $(FAQ_SED_OPTIONS) \ > $@ $(JTREG_README): $(SRCJTREGDOCDIR)/README $(MKDIR) -p $(@D) $(RM) $@ $(CP) $< $@ $(JTREG_TAGSPEC): $(JTREG_IMAGEDIR)/doc/jtreg/%: $(SRCJTREGDOCDIR)/% $(RM) $@ $(MKDIR) -p $(@D) $(CP) $^ $@ $(JTREG_USAGE): $(BUILDDIR)/jtreg-usage.txt $(CP) $^ $@ $(JTREG_LICENSE): $(TOPDIR)/LICENSE $(MKDIR) -p $(@D) $(CP) $^ $@ $(BUILDDIR)/jtreg-usage.txt: \ $(BUILDDIR)/classes.com.sun.javatest.regtest.ok \ $(BUILDDIR)/classes/com/sun/javatest/regtest/tool/i18n.properties \ $(BUILDDIR)/classes/com/sun/javatest/regtest/tool/jars.properties $(JDKJAVA) -cp "$(CLASSDIR)$(PS)$(JAVATEST_JAR)" \ -Dprogram=jtreg com.sun.javatest.regtest.Main -help all > $@ TARGETS.ZIP.jtreg += $(JTREG_DOCS) #---------------------------------------------------------------------- ifdef JAVATEST_SRCDIR JAVATEST_SRCFILES= \ $(JAVATEST_SRCDIR)/com/sun/javatest/InterviewParameters.java \ $(JAVATEST_SRCDIR)/com/sun/javatest/Parameters.java \ $(JAVATEST_SRCDIR)/com/sun/javatest/Status.java \ $(JAVATEST_SRCDIR)/com/sun/javatest/TestDescription.java \ $(JAVATEST_SRCDIR)/com/sun/javatest/TestResult.java \ $(JAVATEST_SRCDIR)/com/sun/javatest/TestResultTable.java \ $(JAVATEST_SRCDIR)/com/sun/javatest/WorkDirectory.java endif $(JTREG_IMAGEDIR)/doc/api/index.html: \ $(JAVAFILES.com.sun.javatest.regtest-tools) \ $(JAVATEST_SRCFILES) $(JDKHOME)/bin/javadoc -d $(@D) \ -encoding ASCII \ -sourcepath "$(JAVADIR)$(PS)$(JAVATEST_SRCDIR)" \ -classpath "$(JAVATEST_JAR)$(PS)$(JUNIT_JAR)$(PS)$(TESTNG_JAR)" \ com.sun.javatest.regtest \ $(JAVATEST_SRCFILES) $(JTREG_IMAGEDIR)/doc/devapi/index.html: \ $(JAVAFILES.com.sun.javatest.regtest-tools) \ $(JAVATEST_SRCFILES) $(JDKHOME)/bin/javadoc -d $(@D) \ -encoding ASCII \ -sourcepath "$(JAVADIR)$(PS)$(JAVATEST_SRCDIR)" \ -classpath "$(JAVATEST_JAR)$(PS)$(JUNIT_CLASSPATH)$(PS)$(TESTNG_CLASSPATH)" \ -subpackages com.sun.javatest.regtest \ -tag "implNote:a:Implementation Note:" \ $(JAVATEST_SRCFILES) #---------------------------------------------------------------------- # # create jtreg.jar PKGS.JAR.jtreg += \ com.sun.javatest.regtest \ com.sun.javatest.regtest.agent \ com.sun.javatest.regtest.config \ com.sun.javatest.regtest.exec \ com.sun.javatest.regtest.report \ com.sun.javatest.regtest.tool \ com.sun.javatest.regtest.util \ java.lang TARGETS.JAR.jtreg += $(TARGETS.com.sun.javatest.regtest) FILES.JAR.jtreg=$(CLASSDIR)/META-INF/services/java.util.spi.ToolProvider $(JTREG_IMAGEDIR)/lib/jtreg.jar: JAR_MAINCLASS = com.sun.javatest.regtest.Main $(JTREG_IMAGEDIR)/lib/jtreg.jar: JAR_CLASSPATH = javatest.jar asmtools.jar $(JTREG_IMAGEJARDIR)/jtreg.jar: \ $(JTREG_IMAGEDIR)/lib/javatest.jar \ $(TARGETS.JAR.jtreg) TARGETS.ZIP.jtreg += $(JTREG_IMAGEJARDIR)/jtreg.jar #---------------------------------------------------------------------- # Import a file to a given directory, and add the target to the list of # dependencies for TARGETS.ZIP.jtreg # 1: the file to be imported # 2: the target directory # define IMPORT_FILE $(2)/$(notdir $(1)): $(call PosixPath,$(1)) $(RM) -f $$@ $(MKDIR) -p $$(@D) $(CP) $$< $$@ TARGETS.ZIP.jtreg += $(2)/$(notdir $(1)) endef #---------------------------------------------------------------------- # # import JavaTest or JT Harness TARGETS.com.sun.javatest.regtest += $(RESOURCES.com.sun.javatest.regtest) $(JTREG_IMAGEDIR)/lib/javatest.jar: $(call PosixPath,$(JAVATEST_JAR)) $(RM) -f $@ $(MKDIR) -p $(@D) $(CP) $< $@ TARGETS.ZIP.jtreg += $(JTREG_IMAGEJARDIR)/javatest.jar $(foreach file,$(JTHARNESS_NOTICES),$(eval $(call IMPORT_FILE,$(file),$(JTREG_IMAGEDIR)/legal/jtharness))) #---------------------------------------------------------------------- # # import JUnit $(foreach jar,$(JUNIT_JARS),$(eval $(call IMPORT_FILE,$(jar),$(JTREG_IMAGEDIR)/lib))) $(foreach file,$(JUNIT_NOTICES),$(eval $(call IMPORT_FILE,$(file),$(JTREG_IMAGEDIR)/legal/junit))) #---------------------------------------------------------------------- # # import TestNG $(foreach jar,$(TESTNG_JARS),$(eval $(call IMPORT_FILE,$(jar),$(JTREG_IMAGEDIR)/lib))) $(foreach file,$(TESTNG_NOTICES),$(eval $(call IMPORT_FILE,$(file),$(JTREG_IMAGEDIR)/legal/testng))) #---------------------------------------------------------------------- # # import AsmTools $(eval $(call IMPORT_FILE,$(ASMTOOLS_JAR),$(JTREG_IMAGEDIR)/lib)) $(JTREG_IMAGEDIR)/lib/jtreg.jar: $(JTREG_IMAGEDIR)/lib/$(notdir $(ASMTOOLS_JAR)) $(foreach file,$(ASMTOOLS_NOTICES),$(eval $(call IMPORT_FILE,$(file),$(JTREG_IMAGEDIR)/legal/asmtools))) #---------------------------------------------------------------------- # # convenience aggregate value for tests ALL_JTREG_JARS = \ $(JTREG_IMAGEDIR)/lib/jtreg.jar \ $(JTREG_IMAGEDIR)/lib/javatest.jar \ $(addprefix $(JTREG_IMAGEDIR)/lib/,$(notdir $(ASMTOOL_JAR))) \ $(addprefix $(JTREG_IMAGEDIR)/lib/,$(notdir $(ASMTOOL_JAR))) \ $(addprefix $(JTREG_IMAGEDIR)/lib/,$(notdir $(JUNIT_JARS))) \ $(addprefix $(JTREG_IMAGEDIR)/lib/,$(notdir $(TESTNG_JARS))) \ #---------------------------------------------------------------------- # # executable scripts $(JTREG_IMAGEDIR)/bin/jtreg: $(SRCSHAREBINDIR)/jtreg.sh $(MKDIR) -p $(@D) $(RM) $@ $(CP) $< $@ $(CHMOD) a+x,a-w $@ TARGETS.ZIP.jtreg += \ $(JTREG_IMAGEDIR)/bin/jtreg #---------------------------------------------------------------------- # # release info # based on code in OpenJDK make/SourceRevision.gmk ID_COMMAND := $(PRINTF) "git:%s%s\n" \ "$$(git log -n1 --format=%H | cut -c1-12)" \ "$$(if test -n "$$(git status --porcelain)"; then printf '+'; fi)" $(JTREG_IMAGEDIR)/release: echo "JTREG_VERSION=$(BUILD_VERSION) $(BUILD_NUMBER)" > $@ echo "BUILD_DATE=`/bin/date +'%B %d, %Y'`" >> $@ if [ -r $(TOPDIR)/.git ]; then \ echo "SOURCE=$$($(ID_COMMAND))" >> $@ ; \ elif [ -n "$(SRCREV)" -a -r $(SRCREV) ]; then \ echo "SOURCE=\"$$($(CAT) $(SRCREV) | $(SED) -e 's/:/:git:/' -e 's/ *$$//')\"" >> $@ ; \ fi TARGETS.ZIP.jtreg += \ $(JTREG_IMAGEDIR)/release #---------------------------------------------------------------------- # # create jtreg.zip bundles JTREG_ZIP = $(IMAGES_DIR)/jtreg.zip $(JTREG_ZIP): $(TARGETS.ZIP.jtreg) $(RM) $@ cd $(IMAGES_DIR); $(ZIP) -rq $@ $(@F:%.zip=%) JTREG_ZIPFILES = $(JTREG_ZIP) #---------------------------------------------------------------------- BUILDFILES += $(JTREG_ZIPFILES) VERBOSEZIPFILES += $(JTREG_ZIPFILES:%.zip=%-$(VERBOSE_ZIP_SUFFIX).zip) NEWVERBOSEZIPFILES += $(JTREG_ZIPFILES:%.zip=%-$(NEW_VERBOSE_ZIP_SUFFIX).zip) #JTREG_JAVA_OPTS = -Ddebug.com.sun.javatest.TestResultCache=98 #JTREG_OPTS = $(JTREG_JAVA_OPTS:%=-J%) TESTS += $(TESTS.jtreg) jtreg-jtreg-7.4-1/make/pkgsToFiles.sh000066400000000000000000000026151461415321300174550ustar00rootroot00000000000000#! /bin/sh # # Copyright (c) 2001, 2013, 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. Oracle designates this # particular file as subject to the "Classpath" exception as provided # by Oracle in the LICENSE file that accompanied this code. # # 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. # classdir=$1; shift cd $classdir if [ "$#" -gt 0 ]; then for i in $* ; do dir=`echo $i | sed -e 's|\.|/|g'` ls -F $dir | grep -v '/$' | sed -e 's|\*$||' -e "s|\(.*\)|-C $classdir $dir/\1|" done fi jtreg-jtreg-7.4-1/src/000077500000000000000000000000001461415321300145355ustar00rootroot00000000000000jtreg-jtreg-7.4-1/src/share/000077500000000000000000000000001461415321300156375ustar00rootroot00000000000000jtreg-jtreg-7.4-1/src/share/bin/000077500000000000000000000000001461415321300164075ustar00rootroot00000000000000jtreg-jtreg-7.4-1/src/share/bin/jtreg.sh000066400000000000000000000142731461415321300200650ustar00rootroot00000000000000#!/bin/sh # # Copyright (c) 1998, 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. Oracle designates this # particular file as subject to the "Classpath" exception as provided # by Oracle in the LICENSE file that accompanied this code. # # 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. # # Usage: # jtreg ...args.... # Run the application via the regression test-suite front end # with the given arguments. # The Java runtime used to run jtreg is found as follows: # - $JTREG_JAVA is used, if it is set # - Otherwise, $JAVA_HOME/bin/java is used if $JAVA_HOME is set # (that is, similar to JDK.) # - Otherwise, the value of the -jdk option is used if found # - Otherwise, "java" is used # # jtreg requires a version of Java equivalent to JDK 1.8.0 or higher. # $JTREG_HOME can be used to specify the jtreg installation directory # (e.g. /usr/local/jtreg/5.0) # # $JTREG_JAVA is used to specify the version of java to use when running jtreg # (e.g. /usr/local/java/jdk1.8.0/bin/java) # # You can also run the jar file directly, as in # java -jar /lib/jtreg.jar ...args... # # jtreg also provides Ant tasks; see the documentation for details. # Implementation notes for Windows: # Cygwin: # Detected with `uname -s` (CYGWIN*) # Windows drives are mounted with /cygdrive/LETTER # Windows Subsystem for Linux (WSL): # Detected with `uname -s` (Linux) and /proc/version contains "Microsoft" # Windows drives are mounted with /mnt/LETTER # Windows binaries need an explicit .exe suffix. # # Values are evaluated according to whether they are used in the context of the # shell, or in the context of the JDK under test. # JTREG_JAVA is evaluated for use in the shell, to run java # JTREG_HOME is evaluated as a JDK arg, for use in -classpath or -jar args # Other command line are updated to be JDK args for jtreg. case "`uname -s`" in CYGWIN* ) cygwin=1 ;; Linux ) if grep -qi Microsoft /proc/version ; then wsl=1 ; fi ;; esac # Determine jtreg installation directory JTREG_HOME=${JTREG_HOME:-$JT_HOME} # allow for old version of name if [ -n "$JTREG_HOME" ]; then if [ ! -r $JTREG_HOME/lib/jtreg.jar ];then echo "Invalid JTREG_HOME=$JTREG_HOME. Cannot find or read $JTREG_HOME/lib/jtreg.jar" exit 1; fi else # Deduce where script is installed # - should work on most derivatives of Bourne shell, like ash, bash, ksh, # sh, zsh, etc, including on Windows, MKS (ksh), Cygwin (ash or bash) # and Windows Subsystem for Linux (WSL) if type -p type 1>/dev/null 2>&1 && test -z "`type -p type`" ; then myname=`type -p "$0"` elif type type 1>/dev/null 2>&1 ; then myname=`type "$0" | sed -e 's/^.* is a tracked alias for //' -e 's/^.* is //'` elif whence whence 1>/dev/null 2>&1 ; then myname=`whence "$0"` fi mydir=`dirname "$myname"` p=`cd "$mydir" ; pwd` while [ -n "$p" -a "$p" != "/" ]; do if [ -r "$p"/lib/jtreg.jar ]; then JTREG_HOME="$p" ; break; fi p=`dirname "$p"` done if [ -z "$JTREG_HOME" ]; then echo "Cannot determine JTREG_HOME; please set it explicitly"; exit 1 fi fi # Look for -jdk option as possible default to run jtreg # Unset IFS and use newline as arg separator to preserve spaces in args DUALCASE=1 # for MKS: make case statement case-sensitive (6709498) saveIFS="$IFS" nl=' ' for i in "$@" ; do IFS= case $i in -jdk:* ) jdk="`echo $i | sed -e 's/^-jdk://'`" ;; esac IFS="$saveIFS" done unset DUALCASE # Determine java for jtreg, from JTREG_JAVA, JAVA_HOME, -jdk, java JTREG_JAVA=${JTREG_JAVA:-$JT_JAVA} # allow for old version of name if [ -n "$JTREG_JAVA" ]; then if [ -d "$JTREG_JAVA" ]; then JTREG_JAVA="$JTREG_JAVA/bin/java" fi elif [ -n "$JAVA_HOME" ]; then JTREG_JAVA="$JAVA_HOME/bin/java" elif [ -n "$jdk" ]; then JTREG_JAVA="$jdk/bin/java" else JTREG_JAVA=java fi # Fixup JTREG_JAVA, JTREG_HOME as needed, if using Cygwin or WSL if [ -n "$cygwin" ]; then JTREG_HOME=`cygpath -a -m "$JTREG_HOME"` driveDir=cygdrive elif [ -n "$wsl" -a -x "$JTREG_JAVA".exe ]; then JTREG_JAVA="$JTREG_JAVA".exe JTREG_HOME=`wslpath -a -m "$JTREG_HOME"` driveDir=mnt fi # Verify java version 11 or newer used to run jtreg version=`"$JTREG_JAVA" -classpath "${JTREG_HOME}/lib/jtreg.jar" com.sun.javatest.regtest.agent.GetSystemProperty java.version 2>&1 | grep 'java.version=' | sed -e 's/^.*=//' -e 's/^1\.//' -e 's/\([1-9][0-9]*\).*/\1/'` if [ -z "$version" ]; then echo "Cannot determine version of java to run jtreg" exit 1; elif [ "$version" -lt 11 ]; then echo "java version 11 or later is required to run jtreg" exit 1; fi # Separate out -J* options for the JVM # Unset IFS and use newline as arg separator to preserve spaces in arg DUALCASE=1 # for MKS: make case statement case-sensitive (6709498) saveIFS="$IFS" nl=' ' for i in "$@" ; do IFS= if [ -n "$driveDir" ]; then i=`echo $i | sed -e 's|/'$driveDir'/\([A-Za-z]\)/|\1:/|'` ; fi case $i in -J* ) javaOpts=$javaOpts$nl`echo $i | sed -e 's/^-J//'` ;; * ) jtregOpts=$jtregOpts$nl$i ;; esac IFS="$saveIFS" done unset DUALCASE # And finally ... IFS=$nl "${JTREG_JAVA}" \ $javaOpts \ -Dprogram=`basename "$0"` \ -jar "${JTREG_HOME}/lib/jtreg.jar" \ $jtregOpts jtreg-jtreg-7.4-1/src/share/classes/000077500000000000000000000000001461415321300172745ustar00rootroot00000000000000jtreg-jtreg-7.4-1/src/share/classes/META-INF/000077500000000000000000000000001461415321300204345ustar00rootroot00000000000000jtreg-jtreg-7.4-1/src/share/classes/META-INF/services/000077500000000000000000000000001461415321300222575ustar00rootroot00000000000000jtreg-jtreg-7.4-1/src/share/classes/META-INF/services/java.util.spi.ToolProvider000066400000000000000000000000601461415321300273140ustar00rootroot00000000000000com.sun.javatest.regtest.tool.JtregToolProvider jtreg-jtreg-7.4-1/src/share/classes/com/000077500000000000000000000000001461415321300200525ustar00rootroot00000000000000jtreg-jtreg-7.4-1/src/share/classes/com/sun/000077500000000000000000000000001461415321300206575ustar00rootroot00000000000000jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/000077500000000000000000000000001461415321300225005ustar00rootroot00000000000000jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/000077500000000000000000000000001461415321300241555ustar00rootroot00000000000000jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/BadArgs.java000066400000000000000000000031021461415321300263170ustar00rootroot00000000000000/* * Copyright (c) 2007, 2016, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest; import com.sun.javatest.util.I18NResourceBundle; /** * Exception to report a problem interpreting command line arguments. */ public class BadArgs extends Exception { static final long serialVersionUID = -5835655326361668148L; public BadArgs(I18NResourceBundle i18n, String s, Object... args) { super(i18n.getString(s, args)); } } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/CheckFiles.java000066400000000000000000000133601461415321300270230ustar00rootroot00000000000000/* * Copyright (c) 2005, 2018, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.Set; import com.sun.javatest.finder.CommentStream; import com.sun.javatest.finder.HTMLCommentStream; import com.sun.javatest.finder.JavaCommentStream; import com.sun.javatest.finder.ShScriptCommentStream; /** * Simple utility to check for files containing comments which may contain action tags, * (such as {@code @run}, {@code @compile}, etc.) but which do not contain {@code @test}. * *
 * Usage:
 *     java -cp jtreg.jar:javatest.jar com.sun.javatest.regtest.CheckFiles options... files-or-directories...
 * 
* * One option is supported: *
*
{@code -l}line-length *
the amount of each suspect comment to display *
* *

* After the option, a series of directories and/or files to check can be specified. * Directories will be recursively expanded looking for files to check. * Source-code management directories are ignored. * Files with the following extensions will be checked: {@code .java}, {@code .html}, {@code .sh}. * Other files will be ignored. */ public class CheckFiles { /** * Main entry point. * @param args options, followed by a series of directories or files to check for * possibly-malformed test descriptions. */ public static void main(String[] args) { new CheckFiles().run(args); } /** * Run the utility. * @param args options, followed by a series of directories or files to check for * possibly-malformed test descriptions */ public void run(String[] args) { int i; for (i = 0; i < args.length; i++) { String arg = args[i]; if (arg.equals("-l") && i+1 < args.length) lineLength = Integer.parseInt(args[++i]); else if (arg.startsWith("-")) { System.err.println("bad arg: " + arg); return; } else break; } count = 0; for (i = 0; i < args.length; i++) { File dir = new File(args[i]); scan(dir); } System.err.println(count + " suspect comments found"); } /** * Scan a series of directories and files to check for possibly-malformed test descriptions. * @param files the files to check */ public void scan(File... files) { for (File file : files) { scan(file); } } private void scan(File file) { if (file.isDirectory()) { if (!excludes.contains(file.getName())) scan(file.listFiles()); } else { switch (getExtension(file)) { case JAVA: check(file, new JavaCommentStream()); break; case HTML: check(file, new HTMLCommentStream()); break; case SH: check(file, new ShScriptCommentStream()); break; } } } private void check(File f, CommentStream cs) { try (BufferedReader r = new BufferedReader(new FileReader(f))) { cs.init(r); String comment; while ((comment = cs.readComment()) != null) check(f, comment); } catch (IOException e) { System.err.println("error for " + f + ": " + e); } } private void check(File f, String comment) { comment = comment.replace('\r', ' '); comment = comment.replace('\n', ' '); if (comment.contains("@test")) return; if (comment.matches(".*@(run|main|compile|summary|bug).*")) { System.out.println(f + ": " + comment.substring(0, Math.min(lineLength, comment.length()))); count++; } } private int count; private int lineLength = 80; private static final int HTML = 0; private static final int JAVA = 1; private static final int SH = 2; private static final int OTHER = 3; static int getExtension(File f) { String name = f.getName(); int dot = name.lastIndexOf('.'); if (dot == -1) return OTHER; String e = name.toLowerCase().substring(dot + 1); switch (e) { case "java": return JAVA; case "html": return HTML; case "sh": return SH; default: return OTHER; } } private static final Set excludes = Set.of(".hg", ".git"); } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/Main.java000066400000000000000000000071761461415321300257170ustar00rootroot00000000000000/* * Copyright (c) 1997, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest; import com.sun.javatest.Harness; import com.sun.javatest.regtest.tool.Tool; import com.sun.javatest.util.I18NResourceBundle; import java.io.PrintWriter; /** * Main entry point to be used to access the Regression Test Harness for JDK: jtreg. */ public class Main { /** * Standard entry point. * Only returns if GUI mode is initiated; otherwise, it calls System.exit with an * appropriate exit code. * @param args An array of options and arguments, such as might be supplied on the command line. */ public static void main(String[] args) { Tool.main(args); } // main() /** * Exception to report a problem while running the test harness. */ public static class Fault extends Exception { static final long serialVersionUID = -6780999176737139046L; public Fault(I18NResourceBundle i18n, String s, Object... args) { super(i18n.getString(s, args)); } } /** Execution OK. */ public static final int EXIT_OK = 0; /** No tests found. */ public static final int EXIT_NO_TESTS = 1; /** One or more tests failed. */ public static final int EXIT_TEST_FAILED = 2; /** One or more tests had an error. */ public static final int EXIT_TEST_ERROR = 3; /** Bad user args. */ public static final int EXIT_BAD_ARGS = 4; /** Other fault occurred. */ public static final int EXIT_FAULT = 5; /** Unexpected exception occurred. */ public static final int EXIT_EXCEPTION = 6; public Main() { this(new PrintWriter(System.out, true), new PrintWriter(System.err, true)); } public Main(PrintWriter out, PrintWriter err) { tool = new Tool(out, err); } /** * Decode command line args and perform the requested operations. * @param args An array of args, such as might be supplied on the command line. * @throws BadArgs if problems are found with any of the supplied args * @throws Main.Fault if a serious error occurred during execution * @throws Harness.Fault if exception problems are found while trying to run the tests * @throws InterruptedException if the harness is interrupted while running the tests * @return an exit code: 0 for success, greater than 0 for an error */ public int run(String[] args) throws BadArgs, Fault, Harness.Fault, InterruptedException { return tool.run(args); } private Tool tool; } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/RStatus.java000066400000000000000000000060061461415321300264270ustar00rootroot00000000000000/* * Copyright (c) 2013, 2017, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest; import com.sun.javatest.Status; /** JDK 1.1 factory for normalized status objects. */ public class RStatus { private RStatus() { } public static Status passed(String msg) { return Status.passed(normalize(msg)); } public static Status failed(String msg) { return Status.failed(normalize(msg)); } public static Status error(String msg) { return Status.error(normalize(msg)); } public static Status createStatus(int code, String msg) { return new Status(code, normalize(msg)); } public static Status normalize(Status s) { return new Status(s.getType(), normalize(s.getReason())); } // equivalent to msg.trim().replaceAll("\\s+", " "); private static String normalize(String msg) { boolean ok = true; boolean prevIsWhite = false; for (int i = 0; ok && i < msg.length(); i++) { char ch = msg.charAt(i); if (Character.isWhitespace(ch)) { if (prevIsWhite || ch != ' ' || i == 0) { ok = false; break; } prevIsWhite = true; } else { prevIsWhite = false; } } if (prevIsWhite) ok = false; if (ok) return msg; StringBuilder sb = new StringBuilder(); boolean needWhite = false; for (int i = 0; i < msg.length(); i++) { char ch = msg.charAt(i); if (Character.isWhitespace(ch)) { if (sb.length() > 0) needWhite = true; } else { if (needWhite) sb.append(' '); sb.append(ch); needWhite = false; } } return sb.toString(); } } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/TimeoutHandler.java000066400000000000000000000143211461415321300277450ustar00rootroot00000000000000/* * Copyright (c) 2014, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest; import java.io.File; import java.io.PrintWriter; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.nio.file.Path; import java.util.concurrent.TimeUnit; import com.sun.javatest.regtest.agent.Alarm; /** * Abstract superclass for timeout handlers. * * Instances of this class will be called when an action involving a process has timed out. * jtreg provides a default implementation of this class; * alternative implementation may be specified on the {@code jtreg} command line. */ public abstract class TimeoutHandler { /** * The log to which messages should be written. */ protected final PrintWriter log; /** * The directory in which diagnostic information may be written. */ protected final File outputDir; /** * The JDK being tested. */ protected final File testJdk; private long timeout; /** * Creates a timeout handler. * * @param log to which messages should be written * @param outputDir a directory in which diagnostic information may be written * @param testJdk the JDK being tested */ public TimeoutHandler(PrintWriter log, File outputDir, File testJdk) { this(log, outputDir, testJdk.toPath()); } /** * Creates a timeout handler. * * @param log to which messages should be written * @param outputDir a directory in which diagnostic information may be written * @param testJdk the JDK being tested */ public TimeoutHandler(PrintWriter log, File outputDir, Path testJdk) { this.log = log; this.outputDir = outputDir; this.testJdk = testJdk.toFile(); } /** * Sets the timeout, in seconds, after which the handler itself will be interrupted. * A negative or zero value disables the timeout. * * @param timeout the timeout */ public void setTimeout(long timeout) { this.timeout = timeout; } /** * Gets the timeout, in seconds, after which the handler itself will be interrupted. * A negative or zero value disables the timeout. * * @return the timeout */ public long getTimeout() { return timeout; } /** * Initiates the timeout handler, to analyze a specified process, by calling {@link #runActions}. * The handler itself is subject to a secondary timeout, which can be specified with * {@link #setTimeout}. * * @param proc the process */ public final void handleTimeout(Process proc) { log.println("Timeout information:"); long pid = 0; try { pid = getProcessId(proc); } catch(Exception ex) { ex.printStackTrace(log); } if (pid == 0) { log.println("Could not find process id for the process that timed out."); log.println("Skipping timeout handling."); return; } Alarm a = (timeout <= 0) ? Alarm.NONE : Alarm.scheduleInterrupt(timeout, TimeUnit.SECONDS, log, Thread.currentThread()); try { runActions(proc, pid); } catch (InterruptedException ex) { a.cancel(); log.println("Timeout handler interrupted: "); ex.printStackTrace(log); } finally { a.cancel(); } log.println("--- Timeout information end."); } /** * Performs actions on the process to gather data that can be used to analyze the time out. * * @param process the process that has timed out * @param pid the pid of the process * @throws InterruptedException if the actions exceed the specified timeout */ protected abstract void runActions(Process process, long pid) throws InterruptedException; /** * Gets the process id of the specified process. * * @param proc the process * @return The process id, or 0 if the process id cannot be found */ protected long getProcessId(Process proc) { try { try { Method pid = Process.class.getMethod("pid"); return (Long) pid.invoke(proc); } catch (NoSuchMethodException ignore) { // This exception is expected on pre-JDK 9, // try a fallback method that only works on Unix platforms return getProcessIdPreJdk9(proc); } } catch (ReflectiveOperationException e) { throw new RuntimeException(e); } } private static long getProcessIdPreJdk9(Process proc) throws IllegalAccessException, NoSuchFieldException { if (proc.getClass().getName().equals("java.lang.UNIXProcess")) { int pid; Field f = proc.getClass().getDeclaredField("pid"); boolean oldValue = f.isAccessible(); try { f.setAccessible(true); pid = f.getInt(proc); } finally { f.setAccessible(oldValue); } return pid; } return 0; } } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/agent/000077500000000000000000000000001461415321300252535ustar00rootroot00000000000000jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/agent/AStatus.java000066400000000000000000000310651461415321300275070ustar00rootroot00000000000000/* * Copyright (c) 1996, 2018, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.agent; /** * A class to embody the result of a test: a status-code and a related message. * * This is a reduced copy of {@code com.sun.javatest.Status}, sufficient to the needs * of returning test results from a test VM. In particular, it implements the * same protocol to transfer results across process boundaries, meaning the * encoding of the status type and reason. */ public class AStatus { /** * Create a Status to indicate the successful outcome of a test. * @param reason A short string describing why the test passed. * @return a Status to indicate the successful outcome of a test. */ public static AStatus passed(String reason) { return new AStatus(PASSED, reason); } /** * Create a Status to indicate the unsuccessful outcome of a test: * i.e. the test completed, but the test determined that what was being tested * did not pass the test. * @param reason A short string describing why the test failed. * @return a Status to indicate the unsuccessful outcome of a test. */ public static AStatus failed(String reason) { return new AStatus(FAILED, reason); } /** * Create a Status to indicate that an error occurred while trying to run a test: * i.e. the test did not complete for some reason, and so it could not determine * whether what was being tested passed or failed. * @param reason A short string describing the error that occurred. * @return a Status to indicate the error outcome of a test. */ public static AStatus error(String reason) { return new AStatus(ERROR, reason); } /** * Check if the type code of the status is PASSED. * @return true if the type code is PASSED. * @see #passed * @see #getType * @see #PASSED */ public boolean isPassed() { return (type == PASSED); } /** * Check if the type code of the status is FAILED. * @return true if the type code is FAILED. * @see #failed * @see #getType * @see #FAILED */ public boolean isFailed() { return (type == FAILED); } /** * Check if the type code of the status is ERROR. * @return true if the type code is ERROR. * @see #error * @see #getType * @see #ERROR */ public boolean isError() { return (type == ERROR); } /** * Check if the type code of the status is NOT_RUN. * @return true if the type code is ERROR. * @see #getType * @see #NOT_RUN */ public boolean isNotRun() { return (type == NOT_RUN); } /** * A return code indicating that the test was executed and was successful. * @see #passed * @see #getType */ public static final int PASSED = 0; /** * A return code indicating that the test was executed but the test * reported that it failed. * @see #failed * @see #getType */ public static final int FAILED = 1; /** * A return code indicating that the test was not run because some error * occurred before the test could even be attempted. This is generally * a more serious error than FAILED. * @see #getType */ public static final int ERROR = 2; /** * A return code indicating that the test has not yet been run in this context. * (More specifically, no status file has been recorded for this test in the * current work directory.) This is for the internal use of the harness only. * @see #getType */ public static final int NOT_RUN = 3; /** * Number of states which are predefined as "constants". */ public static final int NUM_STATES = 4; /** * Get the type code indicating the type of this Status object. * @return the type code indicating the type of this Status object. * @see #PASSED * @see #FAILED * @see #ERROR */ public int getType() { return type; } /** * Get the message given when the status was created. * @return the string given when this Status object was created. */ public String getReason() { return reason; } /** * Convert a Status to a string. */ public String toString() { if (reason == null || reason.length() == 0) return texts[type]; else return texts[type] + " " + reason; } /** * Convenience exit() function for the main() of tests to exit in such a * way that the status passes up across process boundaries without losing * information (ie exit codes don't give the associated text of the status * and return codes when exceptions are thrown could cause unintended * results).

* * An identifying marker is written to the error stream, which the script * running the test watches for as the last output before returning, * followed by the type and reason * * The method does not return. It calls System.exit with a value * dependent on the type. */ public void exit() { if (System.err != null) { System.err.print(EXIT_PREFIX); System.err.print(texts[type]); System.err.println(encode(reason)); System.err.flush(); } System.exit(exitCodes[type]); } /** * Create a Status object. See {@link #passed}, {@link #failed}, {@link #error} * etc. for more convenient factory methods to create Status objects. * @param type The type code for the Status object. * @param reason A short string to store in the status. Unprintable * characters (i.e. outside the range 040C to 177C) in the string are * replaced by a space. All whitespace runs are reduced to a single * whitespace. * @throws IllegalArgumentException if the specified type is invalid. */ public AStatus(int type, String reason) throws IllegalArgumentException { if (type < 0 || type >= NUM_STATES) throw new IllegalArgumentException(String.valueOf(type)); this.type = type; this.reason = normalize(reason); } //-----internal routines---------------------------------------------------- // equivalent to msg.trim().replaceAll("\\s+", " "); private static String normalize(String msg) { boolean ok = true; boolean prevIsWhite = false; for (int i = 0; ok && i < msg.length(); i++) { char ch = msg.charAt(i); if (Character.isWhitespace(ch)) { if (prevIsWhite || ch != ' ' || i == 0) { ok = false; break; } prevIsWhite = true; } else { prevIsWhite = false; } } if (prevIsWhite) { ok = false; } if (ok) { return msg; } StringBuilder sb = new StringBuilder(); boolean needWhite = false; for (int i = 0; i < msg.length(); i++) { char ch = msg.charAt(i); if (Character.isWhitespace(ch)) { if (sb.length() > 0) { needWhite = true; } } else { if (needWhite) { sb.append(' '); } sb.append(ch); needWhite = false; } } return sb.toString(); } private static final boolean isPrintable(char c) { return (32 <= c && c < 127); } //----------Data members---------------------------------------------------- private final int type; private final String reason; /** * A string used to prefix the status when it is written to System.err * by {@link #exit}. */ public static final String EXIT_PREFIX = "STATUS:"; private static final String[] texts = { // correspond to PASSED, FAILED, ERROR, NOT_RUN "Passed.", "Failed.", "Error.", "Not run." }; /** * Exit codes used by Status.exit corresponding to * {@code PASSED}, {@code FAILED}, {@code ERROR}, {@code NOT_RUN}. * The only values that should normally be returned from a test * are the first three; the other value is provided for completeness. * Note: The assignment is historical and cannot easily be changed. */ public static final int[] exitCodes = { 95, 97, 98, 99 }; /** * Encodes strings containing non-ascii characters, where all characters * are replaced with their Unicode code. Encoded string will have * the certain prefix and suffix to be distinguished from non-encode one. * Strings of ASCII chars only are encoded into themselves.
* Example: *

{@code
     * System.out.println(Status.encode("X \u01AB")); //58 20 1AB 
     * System.out.println(Status.encode("Abc1")); // Abc1
     * }
* @param str - string to encode * @return Encoded string or the same string if none non-ascii chars were found * * @see #decode(java.lang.String) */ public static String encode(String str) { if (str == null) { return null; } boolean isAscii = true; for (int i = 0; i < str.length(); i++) { if (!isPrintable(str.charAt(i))) { isAscii = false; break; } } if (isAscii) { return str; // no need to decode; } StringBuilder sb = new StringBuilder(); sb.append(ENC_PREFFIX); for (int i = 0; i < str.length(); i++) { sb.append(encodeChar(str.charAt(i))); sb.append(ENC_SEPARATOR); } sb.append(ENC_SUFFFIX); return sb.toString(); } /** * Decodes string encoded by encode(String) method. * @param str - string to decode * @return Decoded string or the same string if encoded prefix/suffix * were found * * @see #encode(java.lang.String) */ public static String decode(String str) { if (str == null) { return null; } int ind = str.indexOf(ENC_PREFFIX); if (ind < 0 || !str.endsWith(ENC_SUFFFIX)) { return str; // not encoded } // identify encoded part String encoded = str.substring(ind + ENC_PREFFIX.length(), str.length() - ENC_SUFFFIX.length()); StringBuilder sb = new StringBuilder(); sb.append(str, 0, ind); // emulate StringTokenizer(encoded, ENC_SEPARATOR) to find tokens int begin = 0; int end = encoded.indexOf(ENC_SEPARATOR); while (end >= 0) { sb.append(decodeChar(encoded.substring(begin, end))); begin = end + ENC_SEPARATOR.length(); end = encoded.indexOf(ENC_SEPARATOR, begin); } sb.append(encoded.substring(begin)); return sb.toString(); } private static String encodeChar(char c) { return Integer.toString((int)c, 16); } private static char decodeChar(String s) { return (char)Integer.parseInt(s, 16); } /** * Prefix signaling that string is encoded */ private static final String ENC_PREFFIX = ""; /** * Suffix signaling that string is encoded */ private static final String ENC_SUFFFIX = ""; /** * Separator of encoded chars */ private static final String ENC_SEPARATOR = " "; } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/agent/ActionHelper.java000066400000000000000000000237751461415321300305110ustar00rootroot00000000000000/* * Copyright (c) 1998, 2018, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.agent; import java.io.PrintStream; import java.io.PrintWriter; import java.io.StringWriter; import java.security.AccessController; import java.security.PrivilegedAction; import java.security.Provider; import java.security.Security; import java.util.Enumeration; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.Properties; import static com.sun.javatest.regtest.agent.AStatus.error; import static com.sun.javatest.regtest.agent.AStatus.passed; @SuppressWarnings("removal") // Security Manager and related APIs public class ActionHelper { // /** * SaveState captures important system state, such as the security manager, * standard IO streams and system properties, and provides a way to * subsequently restore that state. */ static class SaveState { SaveState() { if (sysProps == null) { sysProps = copyProperties(System.getProperties()); } // Save and setup streams for the test stdOut = System.out; stdErr = System.err; // Default Locale locale = Locale.getDefault(); // Save security manager in case changed by test secMgr = System.getSecurityManager(); // If using default security manager, allow props access, and reset dirty bit if (secMgr instanceof RegressionSecurityManager) { RegressionSecurityManager rsm = (RegressionSecurityManager) secMgr; rsm.setAllowPropertiesAccess(true); rsm.resetPropertiesModified(); } securityProviders = Security.getProviders(); } AStatus restore(String testName, AStatus status) { AStatus cleanupStatus = null; // Reset security manager, if necessary // Do this first, to ensure we reset permissions try { if (System.getSecurityManager() != secMgr) { AccessController.doPrivileged((PrivilegedAction) () -> { System.setSecurityManager(secMgr); return null; }); //System.setSecurityManager(secMgr); } } catch (SecurityException e) { // If we cannot reset the security manager, we might not be able to do // much at all -- such as write files. So, be very noisy to the // primary system error stream about this badly behaved test. stdErr.println(); stdErr.println("***"); stdErr.println("*** " + testName); stdErr.println("*** Cannot reset security manager after test"); stdErr.println("*** " + e.getMessage()); stdErr.println("***"); stdErr.println(); cleanupStatus = error(AGENTVM_CANT_RESET_SECMGR + ": " + e); } try { final Provider[] sp = Security.getProviders(); if (!equal(securityProviders, sp)) { AccessController.doPrivileged((PrivilegedAction) () -> { for (Provider p : sp) { Security.removeProvider(p.getName()); } for (Provider p : securityProviders) { Security.addProvider(p); } return null; }); } } catch (SecurityException e) { cleanupStatus = error(AGENTVM_CANT_RESET_SECPROVS + ": " + e); } // Reset system properties, if necessary // The default security manager tracks whether system properties may have // been written: if so, we reset all the system properties, otherwise // we just reset important props that were written in the test setup boolean resetAllSysProps; SecurityManager sm = System.getSecurityManager(); if (sm instanceof RegressionSecurityManager) { resetAllSysProps = ((RegressionSecurityManager) sm).isPropertiesModified(); } else { resetAllSysProps = true; } try { if (resetAllSysProps) { System.setProperties(newProperties(sysProps)); // System.err.println("reset properties"); } else { System.setProperty("java.class.path", (String) sysProps.get("java.class.path")); // System.err.println("no need to reset properties"); } } catch (SecurityException e) { if (cleanupStatus == null) { cleanupStatus = error(AGENTVM_CANT_RESET_PROPS + ": " + e); } } // Reset output streams AStatus stat = redirectOutput(stdOut, stdErr); if (cleanupStatus == null && !stat.isPassed()) { cleanupStatus = stat; } // Reset locale if (locale != Locale.getDefault()) { Locale.setDefault(locale); } return (cleanupStatus != null ? cleanupStatus : status); } final SecurityManager secMgr; final PrintStream stdOut; final PrintStream stdErr; final Locale locale; final Provider[] securityProviders; static Map sysProps; } private static boolean equal(T[] a, T[] b) { if (a == null || b == null) { return a == b; } if (a.length != b.length) { return false; } for (int i = 0; i < a.length; i++) { if (a[i] != b[i]) { return false; } } return true; } //----------for saving/restoring properties--------------------------------- private static Map copyProperties(Properties p) { Map h = new HashMap<>(); for (Enumeration e = p.propertyNames(); e.hasMoreElements(); ) { Object key = e.nextElement(); h.put(key, p.get(key)); } return h; } private static Properties newProperties(Map h) { Properties p = new Properties(); p.putAll(h); return p; } // //----------output handler-------------------------------------------------- /** * OutputHandler provides an abstract way to get the streams used to record * the output from an action of a test. */ public interface OutputHandler { enum OutputKind { LOG(""), STDOUT("System.out"), STDERR("System.err"), DIRECT("direct"), DIRECT_LOG("direct.log"); OutputKind(String name) { this.name = name; } public final String name; } PrintStream getPrintStream(OutputKind kind, boolean autoFlush); PrintWriter getPrintWriter(OutputKind kind, boolean autoFlush); } //----------in memory streams----------------------------------------------- public static class PrintStringWriter extends PrintWriter { public PrintStringWriter() { super(new StringWriter()); w = (StringWriter) out; } public String getOutput() { return w.toString(); } private final StringWriter w; } //----------redirect streams------------------------------------------------ // if we wanted to allow more concurrency, we could try and acquire a lock here protected static AStatus redirectOutput(PrintStream out, PrintStream err) { synchronized (System.class) { SecurityManager sc = System.getSecurityManager(); if (sc instanceof RegressionSecurityManager) { boolean prev = ((RegressionSecurityManager) sc).setAllowSetIO(true); System.setOut(out); System.setErr(err); ((RegressionSecurityManager) sc).setAllowSetIO(prev); } else { //return Status.error(MAIN_SECMGR_BAD); System.setOut(out); System.setErr(err); } } return passed("OK"); } // redirectOutput() protected static final String EXEC_ERROR_CLEANUP = "Error while cleaning up threads after test", EXEC_PASS = "Execution successful", UNEXPECT_SYS_EXIT = "Unexpected exit from test", AGENTVM_CANT_RESET_SECMGR = "Cannot reset security manager", AGENTVM_CANT_RESET_SECPROVS = "Cannot reset security providers", AGENTVM_CANT_RESET_PROPS = "Cannot reset system properties"; } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/agent/AgentServer.java000066400000000000000000000470721461415321300303550ustar00rootroot00000000000000/* * Copyright (c) 2010, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.agent; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.io.PrintWriter; import java.io.Writer; import java.net.InetAddress; import java.net.Socket; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CoderResult; import java.nio.charset.CodingErrorAction; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.EnumMap; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; @SuppressWarnings("removal") // Security Manager and related APIs public final class AgentServer implements ActionHelper.OutputHandler { /** * Main program used to invoke and run the server in child JVMs * @param args command-line arguments, used to configure the server */ public static void main(String... args) { if (traceServer) System.err.println("AgentServer.main"); try { new AgentServer(args).run(); } catch (Throwable e) { e.printStackTrace(System.err); System.exit(1); } } public static final boolean traceServer = Flags.get("traceServer"); public static final String ALLOW_SET_SECURITY_MANAGER = "-allowSetSecurityManager"; public static final String ID = "-id"; public static final String LOGFILE = "-logfile"; public static final String HOST = "-host"; public static final String PORT = "-port"; public static final String TIMEOUTFACTOR = "-timeoutFactor"; public static final String CUSTOM_TEST_THREAD_FACTORY = "-testThreadFactory"; public static final String CUSTOM_TEST_THREAD_FACTORY_PATH = "-testThreadFactoryPath"; public static final byte DO_COMPILE = 1; public static final byte DO_MAIN = 2; public static final byte OUTPUT = 3; public static final byte STATUS = 4; public static final byte KEEPALIVE = 5; public static final byte CLOSE = 6; /** * Send KEEPALIVE bytes periodically to a stream. * The bytes are written every {@code WRITE_TIMEOUT} milliseconds. * The client reading the stream may use {@code READ_TIMEOUT} as a * corresponding timeout to determine if the sending has stopped * sending KEEPALIVE bytes. */ public static class KeepAlive { public static final int WRITE_TIMEOUT = 60 * 1000; // 1 minute public static final int READ_TIMEOUT = 2 * WRITE_TIMEOUT; public KeepAlive(DataOutputStream out, boolean trace) { this.out = out; this.trace = trace; } public synchronized void setEnabled(boolean on) { alarm.cancel(); if (on) { alarm = Alarm.schedule(WRITE_TIMEOUT, TimeUnit.MILLISECONDS, null, ping); } else { alarm = Alarm.NONE; } } public synchronized void finished() { setEnabled(false); } final DataOutputStream out; final Runnable ping = new Runnable() { @Override public void run() { try { synchronized (out) { if (trace) traceOut.println("KeepAlive.ping"); out.writeByte(KEEPALIVE); out.flush(); } setEnabled(true); } catch (IOException e) { } } }; Alarm alarm = Alarm.NONE; final PrintStream traceOut = System.err; final boolean trace; } private float timeoutFactor = 1.0f; private String testThreadFactory; private String testThreadFactoryPath; public AgentServer(String... args) throws IOException { if (traceServer) { traceOut.println("Agent.Server started"); } boolean allowSetSecurityManagerFlag = false; // by default use loopback address. if "-host" is specified, this will // then be overridden by that value InetAddress host = InetAddress.getLoopbackAddress(); int id = 0; int port = -1; File logFile = null; for (int i = 0; i < args.length; i++) { String arg = args[i]; if (arg.equals(ID)) { try { id = Integer.parseInt(args[++i]); } catch (NumberFormatException e) { id = 0; } } else if (arg.equals(LOGFILE)) { logFile = new File(args[++i]); } else if (arg.equals(ALLOW_SET_SECURITY_MANAGER)) { allowSetSecurityManagerFlag = true; } else if (arg.equals(PORT) && i + 1 < args.length) { port = Integer.valueOf(args[++i]); } else if (arg.equals(HOST) && i + 1 < args.length) { host = InetAddress.getByName(args[++i]); } else if (arg.equals(TIMEOUTFACTOR) && i + 1 < args.length) { timeoutFactor = Float.valueOf(args[++i]); } else if (arg.equals(CUSTOM_TEST_THREAD_FACTORY) && i + 1 < args.length) { testThreadFactory = args[++i]; } else if (arg.equals(CUSTOM_TEST_THREAD_FACTORY_PATH) && i + 1 < args.length) { testThreadFactoryPath = args[++i]; } else { throw new IllegalArgumentException(arg); } } this.id = id; PrintWriter pw = null; if (logFile != null) { try { pw = new PrintWriter(new FileWriter(logFile)); } catch (IOException e) { traceOut.println("Cannot open log writer: " + e); pw = new PrintWriter(System.err) { @Override public void close() { flush(); } }; } } logWriter = pw; log("Started"); if (port > 0) { log("Connecting to " + host + ":" + port); Socket s = new Socket(host, port); s.setSoTimeout((int)(KeepAlive.READ_TIMEOUT * timeoutFactor)); in = new DataInputStream(new BufferedInputStream(s.getInputStream())); out = new DataOutputStream(new BufferedOutputStream(s.getOutputStream())); log("Listening for commands at " + s.getLocalSocketAddress()); } else { in = new DataInputStream(new BufferedInputStream(System.in)); out = new DataOutputStream(new BufferedOutputStream(System.out)); } keepAlive = new KeepAlive(out, traceServer); RegressionSecurityManager.install(); SecurityManager sm = System.getSecurityManager(); if (sm instanceof RegressionSecurityManager) { RegressionSecurityManager rsm = (RegressionSecurityManager) sm; rsm.setAllowPropertiesAccess(true); if (allowSetSecurityManagerFlag) { rsm.setAllowSetSecurityManager(true); } rsm.setAllowSetIO(true); } } public void run() throws IOException { log("Running"); try { int op; while ((op = in.read()) != -1) { switch (op) { case DO_COMPILE: doCompile(); break; case DO_MAIN: doMain(); break; case KEEPALIVE: break; case CLOSE: return; default: // Thread.dumpStack(); throw new Error("Agent.Server: unexpected op: " + op); } out.flush(); } } finally { keepAlive.finished(); log("Exiting"); logWriter.close(); } } private void doCompile() throws IOException { if (traceServer) { traceOut.println("Agent.Server.doCompile"); } // See corresponding list in Agent.doCompile String testName = in.readUTF(); Map testProps = readMap(in); List cmdArgs = readList(in); log(testName + ": starting compilation"); keepAlive.setEnabled(true); try { AStatus status = CompileActionHelper.runCompile(testName, testProps, cmdArgs, 0, this); writeStatus(status); } finally { keepAlive.setEnabled(false); log(testName + ": finished compilation"); } if (traceServer) { traceOut.println("Agent.Server.doCompile DONE"); } } private void doMain() throws IOException { if (traceServer) { traceOut.println("Agent.Server.doMain"); } // See corresponding list in Agent.doMainAction String testName = in.readUTF(); Map testProps = readMap(in); Set addExports = readSet(in); Set addOpens = readSet(in); Set addMods = readSet(in); SearchPath classPath = new SearchPath(in.readUTF()); SearchPath modulePath = new SearchPath(in.readUTF()); String className = in.readUTF(); List classArgs = readList(in); if (traceServer) { traceOut.println("Agent.Server.doMain: " + testName); } log(testName + ": starting execution of " + className); keepAlive.setEnabled(true); try { AStatus status = new MainActionHelper(testName) .properties(testProps) .addExports(addExports) .addOpens(addOpens) .addMods(addMods) .classpath(classPath) .modulepath(modulePath) .className(className) .classArgs(classArgs) .timeout(0) .timeoutFactor(timeoutFactor) .testThreadFactory(testThreadFactory) .testThreadFactoryPath(testThreadFactoryPath) .outputHandler(this) .runClass(); writeStatus(status); } finally { keepAlive.setEnabled(false); log(testName + ": finished execution of " + className); } if (traceServer) { traceOut.println("Agent.Server.doMain DONE"); } } static List readList(DataInputStream in) throws IOException { int n = in.readShort(); List l = new ArrayList<>(n); for (int i = 0; i < n; i++) l.add(in.readUTF()); return l; } static Set readSet(DataInputStream in) throws IOException { int n = in.readShort(); Set s = new LinkedHashSet<>(n); for (int i = 0; i < n; i++) s.add(in.readUTF()); return s; } static Map readMap(DataInputStream in) throws IOException { int n = in.readShort(); Map p = new HashMap<>(n, 1.0f); for (int i = 0; i < n; i++) { String key = in.readUTF(); String value = in.readUTF(); p.put(key, value); } return p; } private void writeStatus(AStatus s) throws IOException { if (traceServer) { traceOut.println("Agent.Server.writeStatus: " + s); } synchronized (out) { out.writeByte(STATUS); out.writeByte(s.getType()); out.writeUTF(s.getReason()); } writers.clear(); } // This format is also used by Agent.java in the client-side log messages. // The format is like this: // 2016-12-21 13:19:46,998 // It is "sort-friendly" so that the lines in all the logs for a test run // can be merged and sorted into a single log. public static final SimpleDateFormat logDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,SSS"); void log(String message) { logWriter.printf("[%s] AgentServer[%d]: %s%n", AgentServer.logDateFormat.format(new Date()), id, message); logWriter.flush(); } private final KeepAlive keepAlive; private final DataInputStream in; private final DataOutputStream out; private final PrintStream traceOut = System.err; private final PrintWriter logWriter; private final int id; private final Map writers = new EnumMap<>(OutputKind.class); /** * Create an output stream for output to be sent back to the client via the server connection. * @param kind the kind of stream * @return the output stream */ public PrintWriter getPrintWriter(OutputKind kind, boolean autoFlush) { return new PrintWriter(getWriter(kind), autoFlush); } private Writer getWriter(final OutputKind kind) { Writer w = writers.get(kind); if (w == null) { w = new Writer() { @Override public void write(char[] cbuf, int off, int len) throws IOException { if (traceServer) { traceOut.println("Agent.Server.write[" + kind + ",writer] " + new String(cbuf, off, len)); } final int BLOCKSIZE = 4096; while (len > 0) { int n = len > BLOCKSIZE ? BLOCKSIZE : len; synchronized (out) { out.writeByte(OUTPUT); out.writeUTF(kind.name); out.writeUTF(new String(cbuf, off, n)); } off += n; len -= n; } if (traceServer) { traceOut.println("Agent.Server.write[" + kind + ",writer]--done"); } } @Override public void flush() throws IOException { out.flush(); } @Override public void close() throws IOException { out.flush(); } }; writers.put(kind, w); } return w; } /** * Create an output stream for output to be sent back to the client via the server connection, * and use it to write the given content. * @param kind the kind of stream * @param autoFlush whether or not to flush the stream on '\n' */ public PrintStream getPrintStream(OutputKind kind, boolean autoFlush) { return new PrintStream(getOutputStream(kind), autoFlush); } private OutputStream getOutputStream(final OutputKind kind) { final Writer w = getWriter(kind); return new OutputStream() { private static final int BUFSIZE = 1024; private ByteBuffer byteBuffer = ByteBuffer.allocate(BUFSIZE); private CharBuffer charBuffer = CharBuffer.allocate(BUFSIZE); private CharsetDecoder decoder = Charset.forName( System.getProperty("sun.stdout.encoding", System.getProperty("sun.jnu.encoding", Charset.defaultCharset().name()))) .newDecoder() .onMalformedInput(CodingErrorAction.REPLACE) .onUnmappableCharacter(CodingErrorAction.REPLACE); @Override public void write(byte[] bytes, int off, int len) throws IOException { if (traceServer) { traceOut.println("Agent.Server.write[" + kind + ",stream] " + new String(bytes, off, len)); } int n; while (len > 0 && len >= (n = byteBuffer.remaining())) { byteBuffer.put(bytes, off, n); decode(); off += n; len -= n; } byteBuffer.put(bytes, off, len); if (traceServer) { traceOut.println("Agent.Server.write[" + kind + ",stream]--done"); } } @Override public void write(int b) throws IOException { byteBuffer.put((byte) b); if (!byteBuffer.hasRemaining()) { decode(); } } @Override public void flush() throws IOException { decode(); // let any content that has been decoded into the charBuffer be written out // to the writer so that the writer can then flush it to underlying stream writeCharBuffer(); w.flush(); } @Override public void close() throws IOException { decode(); byteBuffer.flip(); decoder.decode(byteBuffer, charBuffer, true); writeCharBuffer(); w.flush(); } private void decode() throws IOException { byteBuffer.flip(); CoderResult cr; // The decoder has been configured to replace unmappable character and // malformed input, so this decoder.decode() will only report either // UNDERFLOW or OVERFLOW. // We transfer the decoded content in charBuffer to the writer only when the // charBuffer is full. i.e. the decoder.decode() reports OVERFLOW. In the case of // UNDERFLOW, we keep the decoded content in the charBuffer, until either this // OutputStream instance is flushed or additional data is written into this // OutputStream and the resultant decode() operation results in an OVERFLOW while ((cr = decoder.decode(byteBuffer, charBuffer, false)) != CoderResult.UNDERFLOW) { writeCharBuffer(); } byteBuffer.compact(); } private void writeCharBuffer() throws IOException { charBuffer.flip(); w.write(charBuffer.toString()); charBuffer.clear(); } }; } } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/agent/Alarm.java000066400000000000000000000174531461415321300271640ustar00rootroot00000000000000/* * Copyright (c) 2010, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.agent; import java.io.PrintWriter; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; /** * Provides a lightweight way of setting up and canceling timeouts. */ public class Alarm { /** * Schedule an Alarm to periodically interrupt() a specified thread. * The first interrupt() will happen after the time specified by {@code delay} * and {@code delayUnit}. Thereafter the thread will be interrupted every 100ms * until the Alarm is canceled. * @param delay run the first interrupt after this time * @param unit TimeUnit for {@code delay} * @param msgOut PrintWriter for logging * @param threadToInterrupt The thread to call interrupt() on * @return a new Alarm instance */ public static Alarm schedulePeriodicInterrupt(long delay, TimeUnit unit, PrintWriter msgOut, final Thread threadToInterrupt) { Interruptor runner = new Interruptor(delay, unit, msgOut, threadToInterrupt); runner.future = executor .scheduleWithFixedDelay(runner, TimeUnit.MILLISECONDS.convert(delay, unit), 100, TimeUnit.MILLISECONDS); return runner; } /** * Schedule an Alarm to interrupt() a specified thread. * The interrupt() will happen after the time specified by {@code delay} * and {@code delayUnit}. * @param delay run the interrupt after this time * @param unit TimeUnit for {@code delay} * @param msgOut PrintWriter for logging * @param threadToInterrupt The thread to call interrupt() on * @return a new Alarm instance */ public static Alarm scheduleInterrupt(long delay, TimeUnit unit, PrintWriter msgOut, final Thread threadToInterrupt) { Interruptor runner = new Interruptor(delay, unit, msgOut, threadToInterrupt); runner.future = executor.schedule(runner, delay, unit); return runner; } /** * Schedule an Alarm to run the specified Runnable. * The Runnable will be run after the time specified by {@code delay} * and {@code delayUnit}. * * Note: Because Alarms are serviced by just a single thread, Alarm actions must * be quick so that other Alarms are not blocked from running as scheduled. * * @param delay run after this time * @param unit TimeUnit for {@code delay} * @param msgOut PrintWriter for logging * @param r the Runnable * @return a new Alarm instance */ public static Alarm schedule(long delay, TimeUnit unit, PrintWriter msgOut, Runnable r) { RunnableAlarm runner = new RunnableAlarm(delay, unit, msgOut, r); runner.future = executor.schedule(runner, delay, unit); return runner; } protected volatile boolean fired; protected ScheduledFuture future; protected int count; protected final long delay; protected final TimeUnit delayUnit; protected final PrintWriter msgOut; /** * Internal constructor. * @param delay run the interrupt after this time * @param delayUnit TimeUnit for {@code delay} * @param msgOut PrintWriter for logging */ protected Alarm(long delay, TimeUnit delayUnit, PrintWriter msgOut) { this.delay = delay; this.delayUnit = delayUnit; this.msgOut = msgOut; } /** * Cancel the Alarm. */ public void cancel() { future.cancel(true); } /** * Check if the Alarm has fired at least once. * @return true if the alarm has fired, false otherwise */ public boolean didFire() { return fired; } /** * Shared logic for all Alarms */ protected void run() { if (msgOut != null) { if (count == 0) { msgOut.println(String.format("Timeout signalled after %d seconds", TimeUnit.SECONDS.convert(delay, delayUnit))); } else if (count % 100 == 0) { msgOut.println(String.format("Timeout refired %d times", count)); } } count++; fired = true; } /** * Helper class to implement the Thread.interrupt() calls. */ private static class Interruptor extends Alarm implements Runnable { Thread threadToInterrupt; public Interruptor(long delay, TimeUnit unit, PrintWriter msgOut, Thread t) { super(delay, unit, msgOut); threadToInterrupt = t; } @Override public void run() { super.run(); threadToInterrupt.interrupt(); } } /** * Helper class to run a Runnable. */ private static class RunnableAlarm extends Alarm implements Runnable { Runnable r; public RunnableAlarm(long delay, TimeUnit unit, PrintWriter msgOut, Runnable r) { super(delay, unit, msgOut); this.r = r; } @Override public void run() { super.run(); r.run(); } } /** * An Alarm instance that can be used to initialize an Alarm variable. * This instance of Alarm will never fire. */ public static final Alarm NONE = new NoAlarm(0, TimeUnit.MILLISECONDS, null); private static class NoAlarm extends Alarm { protected NoAlarm(long delay, TimeUnit delayUnit, PrintWriter msgOut) { super(delay, delayUnit, msgOut); } @Override public void cancel() { } @Override public boolean didFire() { return false; } } /** * Our own ThreadFactory to make the thread in the pool be a daemon threads. */ private static class DaemonThreadFactory implements ThreadFactory { ThreadFactory defaultFactory = Executors.defaultThreadFactory(); @Override public Thread newThread(Runnable r) { Thread thread = defaultFactory.newThread(r); thread.setDaemon(true); return thread; } } private static final ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1, new DaemonThreadFactory()); } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/agent/AppletWrapper.java000066400000000000000000000566361461415321300307240ustar00rootroot00000000000000/* * Copyright (c) 1998, 2017, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.agent; import java.applet.Applet; import java.applet.AppletContext; import java.applet.AppletStub; import java.awt.BorderLayout; import java.awt.Button; import java.awt.Checkbox; import java.awt.CheckboxGroup; import java.awt.Component; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Font; import java.awt.Frame; import java.awt.Graphics; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.Label; import java.awt.Panel; import java.awt.TextArea; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.FileReader; import java.io.IOException; import java.io.StringWriter; import java.lang.reflect.Method; import java.net.URL; import java.util.Map; import java.util.HashMap; /** * This class is the wrapper for all applet tests. */ @SuppressWarnings("removal") // Applet and related APIs public class AppletWrapper { public static void main(String[] args) { String[] appArgs; try { FileReader in = new FileReader(args[0]); StringWriter out = new StringWriter(); char[] buf = new char[1024]; int howMany; while ((howMany = in.read(buf)) > 0) out.write(buf, 0, howMany); out.close(); in.close(); appArgs = StringArray.splitTerminator("\0", out.toString()); // order determined by the associated write in // AppletAction.runOtherJVM() int i = 0; className = appArgs[i++]; sourceDir = appArgs[i++]; classDir = appArgs[i++]; classpath = appArgs[i++]; manual = appArgs[i++]; body = appArgs[i++]; appletParams = stringToMap(appArgs[i++]); appletAtts = stringToMap(appArgs[i++]); } catch (IOException e) { status = AStatus.failed("JavaTest Error: Can't read applet args file."); status.exit(); } AppletThreadGroup tg = new AppletThreadGroup(); Thread t = new Thread(tg, new AppletRunnable(), "AppletThread"); t.start(); try { t.join(); } catch (InterruptedException e) { status = AStatus.failed("Thread interrupted: " + t); status.exit(); } // never get here because t.run() always calls Status.exit() in the // non-interrupted case } // main() private static Map stringToMap(String s) { String[] pairs = StringArray.splitTerminator("\034", s); Map retVal = new HashMap<>(3); for (int i = 0; i < pairs.length; i+=2) retVal.put(pairs[i], pairs[i+1]); return retVal; } // stringToMap() // // For printing debug messages // private static void Msg(String s) { // System.out.println(Thread.currentThread().getName() + ": " + s); // System.out.println(Thread.currentThread().getThreadGroup()); // } // Msg() static class AppletRunnable implements Runnable { public void run() { waiter = new AppletWaiter(); int width = Integer.parseInt(appletAtts.get("width")); int height = Integer.parseInt(appletAtts.get("height")); AppletFrame app = new AppletFrame(className, body, manual, width, height); Applet applet = app.getApplet(); AppletStubImpl stub = new AppletStubImpl(); applet.setStub(stub); // center the frame app.pack(); Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); Dimension fSize = app.getSize(); app.setLocation(screenSize.width/2 - fSize.width/2, screenSize.height/2 - fSize.height/2); // We want to show the frame which contains the running applet as // soon as possible. If the tests runs a dialog in the init() or // start() that would end up blocking, our frame will still be // shown. app.setVisible(true); applet.init(); validate(applet); stub.isActive = true; applet.start(); app.setVisible(true); validate(app); if (manual.equals("novalue") || manual.equals("unset")) { // short pause for vaguely automated stuff, per the spec // which requires a delay of "a few seconds" at this point try { Thread.sleep(2000); } catch (InterruptedException e) { status = AStatus.failed("Thread interrupted: " + e); status.exit(); } // just in case the system is slow, ensure paint is called applet.paint(app.getApplet().getGraphics()); } else { // wait for user to click on "Pass", "Fail", or "Done" waiter.waitForDone(); } stub.isActive = false; applet.stop(); applet.destroy(); app.dispose(); //Toolkit.getDefaultToolkit().beep(); status.exit(); } // run() private void validate(final Component c) { try { Class eventQueueClass = EventQueue.class; Method isDispatchThread = eventQueueClass.getMethod("isDispatchThread"); Method invokeAndWait = eventQueueClass.getMethod("invokeAndWait", Runnable.class ); if (!((Boolean) (isDispatchThread.invoke(null)))) { invokeAndWait.invoke(null, (Runnable) c::validate); return; } } catch (NoSuchMethodException e) { // must be JDK 1.1 -- fallthrough } catch (Throwable t) { t.printStackTrace(); } c.validate(); } } // class AppletRunnable static class AppletStubImpl implements AppletStub { boolean isActive; public boolean isActive() { return isActive; } public URL getDocumentBase() { throw new UnsupportedOperationException("Not supported yet."); } public URL getCodeBase() { throw new UnsupportedOperationException("Not supported yet."); } public String getParameter(String name) { return appletParams.get(name); } public AppletContext getAppletContext() { throw new UnsupportedOperationException("Not supported yet."); } public void appletResize(int width, int height) { // no-op } } /** * The actual applet being tested is run in its own thread group. * We need to do this so that we can implement * ThreadGroup.uncaughtException() so that we may catch all exceptions from * the test (including those from subsidiary threads). */ static class AppletThreadGroup extends ThreadGroup { AppletThreadGroup() { super("AppletThreadGroup"); } // AppletThreadGroup() public void uncaughtException(Thread t, Throwable e) { // !!!! major simplification - only works for otherJVM // don't have to worry about whether the exception occurred due to // our own cleanup since we always exit at the first exception if (e instanceof ThreadDeath) return; e.printStackTrace(); status = AStatus.failed("Applet thread threw exception: " + e); status.exit(); } // uncaughtException() } // class AppletThreadGroup /** * A GUI object that contains the applet under test and any other GUI * elements as specified by the JDK Test Framework. */ static class AppletFrame extends Frame implements ActionListener { private static final long serialVersionUID = 1L; /** * Create the AppletFrame frame which contains the running applet and * any instructions, buttons, etc. * * @param className The name of the applet class which must extend * java.awt.Applet. * @param text A string containing the test instructions from the body * of the HTML file. * @param manual From the provided test description, an indicator of the * type of the test ("novalue", "unset", "yesno", or "done"). * @param width The width obtained from the HTML applet tag's "width" * attribute. The initial width of the applet. * @param height The height obtained from the HTML applet tag's "height" * attribute. The initial height of the applet. */ public AppletFrame(String className, String text, String manual, int width, int height) { super(className); GridBagLayout gridbag = new GridBagLayout(); setLayout(gridbag); { // "runnning applet:" label GridBagConstraints c = new GridBagConstraints(); c.anchor = GridBagConstraints.WEST; c.gridx = 0; c.gridy = 0; c.gridwidth = 2; c.weightx = 0.0; makeLabel("running applet:", gridbag, c); } { // the applet GridBagConstraints c = new GridBagConstraints(); c.insets = new Insets(3, 3, 3, 3); c.gridx = 0; c.gridy = 1; c.gridwidth = 2; c.fill = GridBagConstraints.BOTH; c.weightx = 1.0; c.weighty = 1.0; makeApplet(className, gridbag, c, width, height); } // consider adding this anonymous class to makeApplet() or just // moving it down to after the layout stuff addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent event) { dispose(); status = AStatus.failed("Test canceled at user request"); status.exit(); } }); if (! manual.equals("novalue") && ! manual.equals("unset")) { { // "applet size:" label and CheckBoxGroup GridBagConstraints c = new GridBagConstraints(); c.insets = new Insets(-3, -3, -3, -3); c.gridx = 0; c.gridy = 2; c.gridwidth = 1; c.weightx = 0.0; c.anchor = GridBagConstraints.WEST; String[] boxNames = {"fixed", "variable"}; makeCheckboxPanel(boxNames, gridbag, c); } /// TAG-SPEC: If /manual is specified, the HTML file itself will be /// displayed. { // "html file instructions:" label GridBagConstraints c = new GridBagConstraints(); c.anchor = GridBagConstraints.WEST; c.gridx = 0; c.gridy = 3; c.gridwidth = 2; makeLabel("html file instructions:", gridbag, c); } { // The body of the html file. GridBagConstraints c = new GridBagConstraints(); c.insets = new Insets(3, 3, 3, 3); c.fill = GridBagConstraints.HORIZONTAL; c.gridx = 0; c.gridy = 4; c.gridwidth = 2; makeTextArea(text, gridbag, c); } { // The buttons. GridBagConstraints c = new GridBagConstraints(); c.insets = new Insets(3, 3, 3, 3); c.gridx = 0; c.gridy = 5; if (manual.equals("yesno")) { c.gridwidth = 1; makeButton("Pass", gridbag, c); c.gridx = 1; makeButton("Fail", gridbag, c); } else { c.gridwidth = 2; makeButton("Done", gridbag, c); } } } // Now that we've figured out what we want to display, let the // layout manager figure out how it wants to display it. validate(); } // AppletFrame() /** * This method is an event handler for our button events. * * @param e The button event. */ public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals("Done")) { status = AStatus.passed(""); } else if (e.getActionCommand().equals("Pass")) { status = AStatus.passed(""); } else if (e.getActionCommand().equals("Fail")) { status = AStatus.failed(""); } else { status = AStatus.failed("Unexpected result"); } // time to go home waiter.done(); } // actionPerformed() //----------accessor methods-------------------------------------------- public Applet getApplet() { return applet; } // getApplet() //----------internal methods-------------------------------------------- private void makeApplet(String className, GridBagLayout gridbag, GridBagConstraints c, int width, int height) { try { Class cls = Class.forName(className); applet = (Applet) cls.newInstance(); } catch (InstantiationException e) { e.printStackTrace(); status = AStatus.error("Unable to instantiate: " + className + " does not extend Applet"); status.exit(); } catch (IllegalAccessException e) { e.printStackTrace(); status = AStatus.error("Illegal access to test: " + className); status.exit(); } catch (ClassNotFoundException e) { e.printStackTrace(); //status = Status.error("JavaTest Error: Class not found: " + // className); status = AStatus.error(e.getMessage()); status.exit(); } // create the panel where the test applet will reside appletPanel = new AppletPanel(applet, width, height); gridbag.setConstraints(appletPanel, c); add(appletPanel, c); } // makeApplet() private void makeButton(String name, GridBagLayout gridbag, GridBagConstraints c) { Button button = new Button(name); gridbag.setConstraints(button, c); add(button); // add a listener to receive events from the button button.addActionListener(this); } // makeButton() private void makeLabel(String name, GridBagLayout gridbag, GridBagConstraints c) { Label label = new Label(name); label.setFont(new Font("Dialog", Font.BOLD, 12)); gridbag.setConstraints(label, c); add(label); } // makeLabel() private void makeTextArea(String name, GridBagLayout gridbag, GridBagConstraints c) { TextArea textArea = new TextArea(name, 16, 80); gridbag.setConstraints(textArea, c); textArea.setEditable(false); add(textArea); } // makeTextArea() private void makeCheckboxPanel(String[] name, GridBagLayout gridbag, GridBagConstraints c) { CheckboxPanel p = new CheckboxPanel(appletPanel, name); gridbag.setConstraints(p, c); add(p); } // makeCheckboxPanel //----------member variables-------------------------------------------- private Applet applet; } // class AppletFrame //----------member variables----------------------------------------------- private static AStatus status = AStatus.passed(""); private static AppletWaiter waiter; private static AppletPanel appletPanel; private static String className; private static String sourceDir; private static String classDir; private static String classpath; private static String manual; private static String body; private static Map appletParams; private static Map appletAtts; } // class AppletWrapper /** * This is the panel which contains the checkboxes which control the behaviour * of the AppletPanel as resize events are sent to the AppletFrame frame. */ class CheckboxPanel extends Panel { private static final long serialVersionUID = 1L; public CheckboxPanel(AppletPanel appletPanel, String[] boxNames) { panel = appletPanel; CheckboxGroup group = new CheckboxGroup(); b1 = new Checkbox(boxNames[0], true, group); b2 = new Checkbox(boxNames[1], false, group); Label label = new Label("applet size:"); label.setFont(new Font("Dialog", Font.BOLD, 12)); add(label); add(b1); add(b2); b1.addItemListener(event -> panel.setFixedSize()); b2.addItemListener(event -> panel.setVariableSize()); } // makeCheckBoxGroup() private Checkbox b1, b2; private AppletPanel panel; } // class CheckboxPanel /** * This is the panel which contains the test applet. */ // @SuppressWarnings("removal") // Applet and related APIs class AppletPanel extends Panel { private static final long serialVersionUID = 1L; AppletPanel(Applet applet, int width, int height) { layout = new GridBagLayout(); setLayout(layout); int inc = 2 * borderWidth; pSize = new Dimension(width + inc, height + inc); mSize = new Dimension(width + inc, height + inc); outerAppletPanel = this; nestedAppletPanel = new NestedAppletPanel(applet); setFixedSize(); this.applet = applet; add(nestedAppletPanel); } // AppletPanel() /** * Method called if the "fixed" checkbox has been selected. The size of the * applet will remain fixed regardless of resize events to the AppletFrame * frame. */ public void setFixedSize() { GridBagConstraints c = new GridBagConstraints(); c.fill = GridBagConstraints.NONE; c.weightx = 0.0; c.weighty = 0.0; // trick: To cause a GUI component resize to take effect immediately, // remove it, change its constraints, then add it back. remove(nestedAppletPanel); layout.setConstraints(nestedAppletPanel, c); add(nestedAppletPanel); // may not be necessary since we should get auto validation on add validate(); } // setFixedSize() /** * Method called if the "variable" checkbox has been selected. The applet * will expand to fill the available space. Resizing the frame will resize * the applet. */ public void setVariableSize() { GridBagConstraints c = new GridBagConstraints(); c.fill = GridBagConstraints.BOTH; c.weightx = 1.0; c.weighty = 1.0; // trick: To cause a GUI component resize to take effect immediately, // remove it, change its constraints, then add it back. remove(nestedAppletPanel); layout.setConstraints(nestedAppletPanel, c); add(nestedAppletPanel); // may not be necessary since we should get auto validation on add validate(); } // setVariableSize() //----------layout manager callbacks---------------------------------------- public Dimension getMinimumSize() { return mSize; } // getMinimumSize() public Dimension getPreferredSize() { return pSize; } // getPreferredSize() public void setSize(int width, int height) { if (initialSize == null) initialSize = getSize(); else if (initialSize != getSize()) { pSize = mSize = getSize(); getParent().invalidate(); getParent().validate(); } } // setSize() public Insets getInsets() { return new Insets(0, 0, 0, 0); } // getInsets() //----------internal classes------------------------------------------------ /** * Class used to manage the geometry of the test applet and to draw a box * around the space available for the applet. */ class NestedAppletPanel extends Panel { private static final long serialVersionUID = 1L; NestedAppletPanel(Applet applet) { setLayout(new BorderLayout()); add(applet, "Center"); } // NestedAppletPanel() public void paint(Graphics g) { g.drawRect(0, 0, getSize().width -1, getSize().height -1); super.paint(g); } // paint() public Dimension getMinimumSize() { return mSize; } // getMinimumSize() public Dimension getPreferredSize() { return pSize; } // getPreferrredSize() public Insets getInsets() { return new Insets(borderWidth, borderWidth, borderWidth, borderWidth); } // getInsets() } // class NestedAppletPanel //----------member variables------------------------------------------------ private Dimension initialSize = null; private Dimension pSize; private Dimension mSize; private static final int borderWidth = 3; private Panel nestedAppletPanel; private Panel outerAppletPanel; private Applet applet; private GridBagLayout layout; } // class AppletPanel /** * Wait until the user indicates that the test has completed. */ class AppletWaiter { public AppletWaiter() { // done = false; } // AppletWaiter() public synchronized void waitForDone() { while (!done) { try { wait(); } catch (InterruptedException e) { AStatus.failed("Thread interrupted: " + e).exit(); } } } // waitForDone(); public synchronized void done() { done = true; notify(); } // done() private boolean done = false; } // class AppletWaiter jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/agent/CompileActionHelper.java000066400000000000000000000117411461415321300320100ustar00rootroot00000000000000/* * Copyright (c) 1998, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.agent; import java.io.PrintStream; import java.io.PrintWriter; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.concurrent.TimeUnit; import static com.sun.javatest.regtest.agent.AStatus.error; import static com.sun.javatest.regtest.agent.AStatus.failed; import static com.sun.javatest.regtest.agent.AStatus.passed; public class CompileActionHelper extends ActionHelper { public static AStatus runCompile(String testName, Map props, List cmdArgs, int timeout, OutputHandler outputHandler) { SaveState saved = new SaveState(); Properties p = System.getProperties(); for (Map.Entry e : props.entrySet()) { String name = e.getKey(); String value = e.getValue(); if (name.equals("test.class.path.prefix")) { SearchPath cp = new SearchPath(value, System.getProperty("java.class.path")); p.put("java.class.path", cp.toString()); } else { p.put(e.getKey(), e.getValue()); } } System.setProperties(p); // RUN THE COMPILER // Setup streams for the test: // ... to catch sysout and syserr PrintStream sysOut = outputHandler.getPrintStream(OutputHandler.OutputKind.STDOUT, true); PrintStream sysErr = outputHandler.getPrintStream(OutputHandler.OutputKind.STDERR, true); // ... for direct use with RegressionCompileCommand PrintWriter out = outputHandler.getPrintWriter(OutputHandler.OutputKind.DIRECT, false); PrintWriter err = outputHandler.getPrintWriter(OutputHandler.OutputKind.DIRECT_LOG, false); AStatus status = error(""); try { AStatus stat = redirectOutput(sysOut, sysErr); if (!stat.isPassed()) { return stat; } Alarm alarm = Alarm.NONE; if (timeout > 0) { PrintWriter alarmOut = outputHandler.getPrintWriter(OutputHandler.OutputKind.LOG, true); alarm = Alarm.schedulePeriodicInterrupt(timeout, TimeUnit.SECONDS, alarmOut, Thread.currentThread()); } try { RegressionCompileCommand jcc = new RegressionCompileCommand() { @Override protected AStatus getStatus(int exitCode) { JDK_Version v = JDK_Version.forThisJVM(); return getStatusForJavacExitCode(v, exitCode); } }; String[] c = cmdArgs.toArray(new String[cmdArgs.size()]); status = jcc.run(c, err, out); } finally { alarm.cancel(); } } finally { out.close(); err.close(); sysOut.close(); sysErr.close(); status = saved.restore(testName, status); } return status; } public static AStatus getStatusForJavacExitCode(JDK_Version v, int exitCode) { if (v == null || v.compareTo(JDK_Version.V1_6) < 0) return (exitCode == 0 ? passed : failed); // The following exit codes are standard in JDK 6 or later switch (exitCode) { case 0: return passed; case 1: return failed; case 2: return error("command line error (exit code 2)"); case 3: return error("system error (exit code 3)"); case 4: return error("compiler crashed (exit code 4)"); default: return error("unexpected exit code from javac: " + exitCode); } } private static final AStatus passed = passed("Compilation successful"); private static final AStatus failed = failed("Compilation failed"); } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/agent/Flags.java000066400000000000000000000027441461415321300271610ustar00rootroot00000000000000/* * Copyright (c) 1998, 2015, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.agent; /** * Debugging and related flags. */ public class Flags { public static boolean get(String name) { return Boolean.getBoolean("javatest.regtest." + name) || (System.getenv("JTREG_" + name.toUpperCase()) != null); } } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/agent/GetJDKProperties.java000066400000000000000000000173241461415321300312520ustar00rootroot00000000000000/* * Copyright (c) 1998, 2018, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.agent; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.concurrent.Callable; /** * Get properties for the JDK under test. * Usage: {@code * java GetJDKProperties [--system-properties] [--modules] * * } */ public class GetJDKProperties { public static class ClientCodeException extends Exception { private static final long serialVersionUID = 0; ClientCodeException(String msg, Throwable t) { super(msg, t); } } public static final String JTREG_MODULES = "jtreg.modules"; public static void main(String... args) { try { run(args); } catch (ClientCodeException e) { System.err.println(e.getMessage()); e.getCause().printStackTrace(System.err); System.exit(1); } catch (Exception e) { System.err.println("Internal error: please report to jtreg-dev@openjdk.org"); e.printStackTrace(System.err); System.exit(1); } } public static void run(String... args) throws ClientCodeException, IOException { boolean needSystemProperties = false; String needModulesArg = null; Properties p = new Properties(); for (String arg: args) { if (arg.equals("--system-properties")) { needSystemProperties = true; } else if (arg.startsWith("--modules=")) { needModulesArg = arg.substring(arg.indexOf("=") + 1); } else { try { @SuppressWarnings("unchecked") Class>> c = (Class>>) Class.forName(arg); Callable> o = c.getDeclaredConstructor().newInstance(); p.putAll(o.call()); } catch (Throwable t) { throw new ClientCodeException("Exception while calling user-specified class: " + arg, t); } } } if (needModulesArg != null && getJDKVersion() >= 9) { String modules = null; if (needModulesArg.equals("boot-layer")) { modules = getModulesFromBootLayer(); } else if (needModulesArg.equals("all-system")) { modules = getAllSystemModules(); } if (modules != null) p.put(JTREG_MODULES, modules); } if (needSystemProperties) { p.putAll(System.getProperties()); } p.store(System.out, "jdk properties"); } private static int getJDKVersion() { String specVersion = System.getProperty("java.specification.version"); if (specVersion == null) return -1; if (specVersion.startsWith("1.")) specVersion = specVersion.substring(2); if (specVersion.contains(".")) specVersion = specVersion.substring(0, specVersion.indexOf(".")); try { return Integer.parseInt(specVersion); } catch (NumberFormatException e) { return -1; } } private static String getModulesFromBootLayer() { try { /* * ModuleLayer bootLayer = ModuleLayer.boot(); * for (Module m : bootLayer.modules()) { * if (sb.length() > ) sb.append(" "); * sb.append(m.getName()); * } */ Class layerClass; try { layerClass = Class.forName("java.lang.ModuleLayer"); } catch (ClassNotFoundException e) { layerClass = Class.forName("java.lang.reflect.Layer"); } Method bootMethod = layerClass.getDeclaredMethod("boot"); Method modulesMethod = layerClass.getDeclaredMethod("modules"); Class moduleClass; try { moduleClass = Class.forName("java.lang.Module"); } catch (ClassNotFoundException e) { moduleClass = Class.forName("java.lang.reflect.Module"); } Method getNameMethod = moduleClass.getDeclaredMethod("getName"); StringBuilder sb = new StringBuilder(); Object bootLayer = bootMethod.invoke(null); for (Object module : (Set) modulesMethod.invoke(bootLayer)) { if (sb.length() > 0) sb.append(" "); sb.append(getNameMethod.invoke(module)); } return sb.toString(); } catch (ClassNotFoundException | IllegalAccessException | IllegalArgumentException | NoSuchMethodException | InvocationTargetException e) { return null; } } private static String getAllSystemModules() { try { /* ModuleFinder f = ModuleFinder.ofSystem(); * for (ModuleReference mr : f.findAll()) { * ModuleDescriptor md = mr.descriptor(); * if (sb.length() > 0 ) * sb.append(" "); * sb.append(md.name()); * } */ Class moduleFinderClass = Class.forName("java.lang.module.ModuleFinder"); Method ofSystemMethod = moduleFinderClass.getDeclaredMethod("ofSystem"); Method findAllMethod = moduleFinderClass.getDeclaredMethod("findAll"); Class moduleReferenceClass = Class.forName("java.lang.module.ModuleReference"); Method descriptorMethod = moduleReferenceClass.getDeclaredMethod("descriptor"); Class moduleDescriptorClass = Class.forName("java.lang.module.ModuleDescriptor"); Method nameMethod = moduleDescriptorClass.getDeclaredMethod("name"); StringBuilder sb = new StringBuilder(); Object systemModuleFinder = ofSystemMethod.invoke(null); for (Object mr : (Set) findAllMethod.invoke(systemModuleFinder)) { Object md = descriptorMethod.invoke(mr); if (sb.length() > 0) sb.append(" "); sb.append(nameMethod.invoke(md)); } return sb.toString(); } catch (ClassNotFoundException | InvocationTargetException | NoSuchMethodException | IllegalArgumentException | IllegalAccessException e) { return null; } } } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/agent/GetSystemProperty.java000066400000000000000000000036211461415321300316110ustar00rootroot00000000000000/* * Copyright (c) 1998, 2015, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.agent; import java.io.IOException; /** * Get a system property */ public class GetSystemProperty { public static void main(String[] args) { if (args.length == 1 && args[0].equals("-all")) { try { System.getProperties().store(System.out, "system properties"); } catch (IOException e) { System.err.println(e); System.exit(1); } } else { for (int i = 0; i < args.length; i++) { String arg = args[i]; String v = System.getProperty(arg); System.out.println(arg + "=" + (v == null ? "" : v)); } } } } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/agent/JDK_Version.java000066400000000000000000000067241461415321300302440ustar00rootroot00000000000000/* * Copyright (c) 2007, 2018, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.agent; import java.util.HashMap; import java.util.Map; public class JDK_Version implements Comparable { private static final Map values = new HashMap<>(); public static JDK_Version V1_1 = JDK_Version.forName("1.1"); public static JDK_Version V1_5 = JDK_Version.forName("1.5"); public static JDK_Version V1_6 = JDK_Version.forName("1.6"); public static JDK_Version V9 = JDK_Version.forName("9"); public static JDK_Version V10 = JDK_Version.forName("10"); public static JDK_Version forName(String name) { if (name == null) return null; synchronized (values) { JDK_Version v = values.get(name); if (v == null) { try { int major; if (name.startsWith("1.")) { major = Integer.parseInt(name.substring(2)); if (major > 10) { // align with javac: allow 1.9, 1.10 return null; } } else { major = Integer.parseInt(name); if (major < 5) { return null; } } values.put(name, v = new JDK_Version(major)); } catch (NumberFormatException e) { return null; } } return v; } } public static JDK_Version forThisJVM() { return forName(System.getProperty("java.specification.version")); } private JDK_Version(int major) { this.major = major; } public final int major; public String name() { return (major < 9 ? "1." : "") + major; } @Override public boolean equals(Object other) { return (other instanceof JDK_Version && (major == ((JDK_Version) other).major)); } @Override public int hashCode() { return major; } @Override public int compareTo(JDK_Version other) { return major < other.major ? -1 : major == other.major ? 0 : 1; } @Override public String toString() { return "JDK " + (major < 9 ? "1." : "") + major; } } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/agent/JUnitRunner.java000066400000000000000000000272221461415321300303460ustar00rootroot00000000000000/* * Copyright (c) 1998, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.agent; import org.junit.platform.engine.TestExecutionResult; import org.junit.platform.engine.TestSource; import org.junit.platform.engine.discovery.DiscoverySelectors; import org.junit.platform.engine.reporting.ReportEntry; import org.junit.platform.engine.support.descriptor.MethodSource; import org.junit.platform.launcher.LauncherDiscoveryRequest; import org.junit.platform.launcher.LauncherSession; import org.junit.platform.launcher.TestExecutionListener; import org.junit.platform.launcher.TestIdentifier; import org.junit.platform.launcher.core.LauncherConfig; import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder; import org.junit.platform.launcher.core.LauncherFactory; import org.junit.platform.launcher.listeners.SummaryGeneratingListener; import org.junit.platform.launcher.listeners.TestExecutionSummary; import java.io.PrintStream; import java.io.PrintWriter; import java.io.StringWriter; import java.lang.reflect.Method; import java.util.Optional; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * TestRunner to run JUnit tests. */ public class JUnitRunner implements MainActionHelper.TestRunner { // error message for when "NoClassDefFoundError" are raised accessing JUnit classes private static final String JUNIT_NO_DRIVER = "No JUnit driver -- install JUnit JAR file(s) next to jtreg.jar"; // this is a temporary flag while transitioning from JUnit 4 to 5 private static final boolean JUNIT_RUN_WITH_JUNIT_4 = Flags.get("runWithJUnit4"); public static void main(String... args) throws Exception { main(null, args); } public static void main(ClassLoader loader, String... args) throws Exception { if (args.length != 2) { throw new Error("wrong number of arguments"); } // String testName = args[0]; // not used String moduleClassName = args[1]; int sep = moduleClassName.indexOf('/'); String moduleName = (sep == -1) ? null : moduleClassName.substring(0, sep); String className = (sep == -1) ? moduleClassName : moduleClassName.substring(sep + 1); // Class mainClass = (loader == null) ? Class.forName(className) : loader.loadClass(className); ClassLoader cl; if (moduleName != null) { Class layerClass; try { layerClass = Class.forName("java.lang.ModuleLayer"); } catch (ClassNotFoundException e) { layerClass = Class.forName("java.lang.reflect.Layer"); } Method bootMethod = layerClass.getMethod("boot"); Object bootLayer = bootMethod.invoke(null); Method findLoaderMth = layerClass.getMethod("findLoader", String.class); cl = (ClassLoader) findLoaderMth.invoke(bootLayer, moduleName); } else if (loader != null) { cl = loader; } else { cl = JUnitRunner.class.getClassLoader(); } Class mainClass = Class.forName(className, false, cl); if (JUNIT_RUN_WITH_JUNIT_4) { runWithJUnit4(mainClass); } else { runWithJUnitPlatform(mainClass); } } private static void runWithJUnit4(Class mainClass) throws Exception { org.junit.runner.Result result; try { result = org.junit.runner.JUnitCore.runClasses(mainClass); } catch (NoClassDefFoundError ex) { throw new Exception(JUNIT_NO_DRIVER, ex); } if (!result.wasSuccessful()) { for (org.junit.runner.notification.Failure failure : result.getFailures()) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); try { pw.println("JavaTest Message: JUnit Failure: " + failure); failure.getException().printStackTrace(pw); } finally { pw.close(); } System.err.println(sw.toString()); } throw new Exception("JUnit test failure"); } } private static void runWithJUnitPlatform(Class mainClass) throws Exception { // https://junit.org/junit5/docs/current/user-guide/#launcher-api-execution Thread.currentThread().setContextClassLoader(mainClass.getClassLoader()); try { // if test.query is set, treat it as a method name to be executed String testQuery = System.getProperty("test.query"); LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request() .selectors(testQuery == null ? DiscoverySelectors.selectClass(mainClass) : DiscoverySelectors.selectMethod(mainClass, testQuery)) .build(); SummaryGeneratingListener summaryGeneratingListener = new SummaryGeneratingListener(); LauncherConfig launcherConfig = LauncherConfig.builder() .addTestExecutionListeners(new PrintingListener(System.err)) .addTestExecutionListeners(summaryGeneratingListener) .build(); try (LauncherSession session = LauncherFactory.openSession(launcherConfig)) { session.getLauncher().execute(request); } TestExecutionSummary summary = summaryGeneratingListener.getSummary(); System.err.println(summarize(summary)); if (summary.getTotalFailureCount() > 0) { throw new Exception("JUnit test failure"); } } catch (NoClassDefFoundError ex) { throw new Exception(JUNIT_NO_DRIVER, ex); } } static String summarize(TestExecutionSummary summary) { StringWriter sw = new StringWriter(); try (PrintWriter pw = new PrintWriter(sw)) { if (summary.getTotalFailureCount() > 0) { pw.println("JavaTest Message: JUnit Platform Failure(s): " + summary.getTotalFailureCount()); } // The format of the following output is assumed in the JUnit SummaryReporter pw.println(); pw.print("[ JUnit Containers: "); pw.print("found " + summary.getContainersFoundCount()); pw.print(", started " + summary.getContainersStartedCount()); pw.print(", succeeded " + summary.getContainersSucceededCount()); pw.print(", failed " + summary.getContainersFailedCount()); pw.print(", aborted " + summary.getContainersAbortedCount()); pw.print(", skipped " + summary.getContainersSkippedCount()); pw.println("]"); pw.print("[ JUnit Tests: "); pw.print("found " + summary.getTestsFoundCount()); pw.print(", started " + summary.getTestsStartedCount()); pw.print(", succeeded " + summary.getTestsSucceededCount()); pw.print(", failed " + summary.getTestsFailedCount()); pw.print(", aborted " + summary.getTestsAbortedCount()); pw.print(", skipped " + summary.getTestsSkippedCount()); pw.println("]"); } return sw.toString(); } static class PrintingListener implements TestExecutionListener { final PrintWriter printer; final Lock lock; PrintingListener(PrintStream stream) { this(new PrintWriter(stream, true)); } PrintingListener(PrintWriter printer) { this.printer = printer; this.lock = new ReentrantLock(); } @Override public void executionSkipped(TestIdentifier identifier, String reason) { if (identifier.isTest()) { String status = "SKIPPED"; String source = toSourceString(identifier); String name = identifier.getDisplayName(); lock.lock(); try { printer.printf("%-10s %s '%s' %s%n", status, source, name, reason); } finally { lock.unlock(); } } } @Override public void executionStarted(TestIdentifier identifier) { if (identifier.isTest()) { String status = "STARTED"; String source = toSourceString(identifier); String name = identifier.getDisplayName(); lock.lock(); try { printer.printf("%-10s %s '%s'%n", status, source, name); } finally { lock.unlock(); } } } @Override public void executionFinished(TestIdentifier identifier, TestExecutionResult result) { lock.lock(); try { TestExecutionResult.Status status = result.getStatus(); if (status == TestExecutionResult.Status.ABORTED) { result.getThrowable().ifPresent(printer::println); // not the entire stack trace } if (status == TestExecutionResult.Status.FAILED) { result.getThrowable().ifPresent(throwable -> throwable.printStackTrace(printer)); } if (identifier.isTest()) { String source = toSourceString(identifier); String name = identifier.getDisplayName(); printer.printf("%-10s %s '%s'%n", status, source, name); } } finally { lock.unlock(); } } @Override public void reportingEntryPublished(TestIdentifier identifier, ReportEntry entry) { lock.lock(); try { printer.println(identifier.getDisplayName() + " -> " + entry.getTimestamp()); entry.getKeyValuePairs().forEach((key, value) -> printer.println(key + " -> " + value)); } finally { lock.unlock(); } } private static String toSourceString(TestIdentifier identifier) { Optional optionalTestSource = identifier.getSource(); if (!optionalTestSource.isPresent()) return ""; TestSource testSource = optionalTestSource.get(); if (testSource instanceof MethodSource) { MethodSource source = (MethodSource) testSource; return source.getClassName() + "::" + source.getMethodName(); } return testSource.toString(); } } } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/agent/JavaTestSecurityManager.java000066400000000000000000000215631461415321300326710ustar00rootroot00000000000000/* * $Id$ * * Copyright (c) 1996, 2018, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.agent; import java.io.FileDescriptor; import java.net.InetAddress; import java.security.Permission; import java.util.PropertyPermission; /** * This class is set for JT Harness running as an application. Currently, it imposes * almost no security restrictions at all: its existence prevents anyone else * (e.g. a test running in this JVM) from setting a more restrictive security manager. * * Although not required for running under JDK1.0.2, extra definitions for forward * compatibility with JDK1.1 are also provided. They will effectively be ignored * by JDK1.0.2. */ @SuppressWarnings("removal") // Security Manager and related APIs public class JavaTestSecurityManager extends SecurityManager { /** * Try to install a copy of this security manager. If another security manager is * already installed, the install will fail; a warning message wil, be written to * the console if the previously installed security manager is not a subtype of * com.sun.javatest.JavaTestSecurityManager. * The install can be suppressed by setting the system property * "javatest.security.noSecurityManager" to true. */ public static void install() { try { // install our own permissive security manager, to prevent anyone else // installing a less permissive one. final String noSecurityMgr = "javatest.security.noSecurityManager"; if (Boolean.getBoolean(noSecurityMgr)) { System.err.println(); System.err.println(" ---- WARNING -----"); System.err.println(); System.err.println("JT Harness did not install its own Security Manager"); System.err.println("because the property " + noSecurityMgr + " was set."); System.err.println("This is not a fatal error, but it may affect the"); System.err.println("execution of sameJVM tests"); System.err.println(); } else { try { // test to see if permission API available: // if it's not, we'll get an exception and load // an old-style security manager Class.forName("java.security.Permission"); System.setSecurityManager(new NewJavaTestSecurityManager()); } catch (ClassNotFoundException e) { System.setSecurityManager(new JavaTestSecurityManager()); } } } catch (SecurityException e) { SecurityManager sm = System.getSecurityManager(); if (!(sm instanceof JavaTestSecurityManager)) { System.err.println(); System.err.println(" ---- WARNING -----"); System.err.println(); System.err.println("JT Harness could not install its own Security Manager"); System.err.println("because of the following exception:"); System.err.println(" " + e); System.err.println("This is not a fatal error, but it may affect the"); System.err.println("execution of sameJVM tests"); System.err.println(); } } } // These are the JDK1.0.2 security methods public void checkAccept(String host, int port) { } public void checkAccess(Thread g) { } public void checkAccess(ThreadGroup g) { } public void checkConnect(String host, int port) { } public void checkConnect(String host, int port, Object context) { } public void checkCreateClassLoader() { } public void checkDelete(String file) { } public void checkExec(String cmd) { } // tests which call System.exit() should not cause JT Harness to exit public void checkExit(int status) { if (allowExit == false) { if (verbose) { System.err.println(getClass().getName() + ": System.exit() forbidden"); new Throwable().printStackTrace(); } throw new SecurityException("System.exit() forbidden by JT Harness"); } } public void checkLink(String lib) { } public void checkListen(int port) { } public void checkPackageAccess(String pkg) { } public void checkPackageDefinition(String pkg) { } // allowing tests to get at and manipulate the system properties // is too dangerous to permit when multiple tests are running, // possibly simultaneously, in the same JVM. public synchronized void checkPropertiesAccess() { if (allowPropertiesAccess == false) { if (verbose) { System.err.println(getClass().getName() + ": properties access forbidden"); new Throwable().printStackTrace(); } throw new SecurityException("Action forbidden by JT Harness: checkPropertiesAccess"); } } public void checkPropertyAccess(String key) { } public void checkRead(FileDescriptor fd) { } public void checkRead(String file) { } public void checkRead(String file, Object context) { } public void checkSetFactory() { } @SuppressWarnings("deprecation") public boolean checkTopLevelWindow(Object window) { return true; } public void checkWrite(FileDescriptor fd) { } public void checkWrite(String file) { } // These methods are added for forward-compatibility with JDK1.1 @SuppressWarnings("deprecation") public void checkAwtEventQueueAccess() { } @SuppressWarnings("deprecation") public void checkMemberAccess(Class clazz, int which) { } public void checkMulticast(InetAddress maddr) { } @SuppressWarnings("deprecation") public void checkMulticast(InetAddress maddr, byte ttl) { } public void checkPrintJobAccess() { } public void checkSecurityAccess(String provider) { } @SuppressWarnings("deprecation") public void checkSystemClipboardAccess() { } /** * Set whether or not the JVM may be exited. The default value is "false". * @param bool true if the JVM may be exited, and false otherwise * @return the previous value of this setting */ public boolean setAllowExit(boolean bool) { boolean prev = allowExit; allowExit = bool; return prev; } /** * Set whether or not the set of system properties may be accessed. * The default value is determined by the system property * "javatest.security.allowPropertiesAccess". * @param bool true if the system properties may be accessed, and false otherwise * @return the previous value of this setting */ public boolean setAllowPropertiesAccess(boolean bool) { boolean prev = allowPropertiesAccess; allowPropertiesAccess = bool; return prev; } static private boolean allowExit = false; // no overrides on this one; API control only static private boolean allowPropertiesAccess = Boolean.getBoolean("javatest.security.allowPropertiesAccess"); static private boolean verbose = Boolean.getBoolean("javatest.security.verbose"); } class NewJavaTestSecurityManager extends JavaTestSecurityManager { public void checkPermission(Permission perm) { // allow most stuff, but limit as appropriate if (perm instanceof RuntimePermission) { if (perm.getName().equals("exitVM")) checkExit(0); if (perm.getName().equals("createSecurityManager")) { super.checkPermission(new java.lang.RuntimePermission("createSecurityManager")); } } else if (perm instanceof PropertyPermission) { if (perm.getActions().equals("read,write")) checkPropertiesAccess(); } } } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/agent/MainActionHelper.java000066400000000000000000000426551461415321300313140ustar00rootroot00000000000000/* * Copyright (c) 1998, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.agent; import java.io.PrintStream; import java.io.PrintWriter; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.concurrent.TimeUnit; import static com.sun.javatest.regtest.agent.AStatus.error; import static com.sun.javatest.regtest.agent.AStatus.failed; import static com.sun.javatest.regtest.agent.AStatus.passed; public class MainActionHelper extends ActionHelper { private final String testName; private Map props; private Set addExports; private Set addOpens; private Set addMods; private SearchPath classpath; private SearchPath modulepath; private String className; private List classArgs; private int timeout; private float timeoutFactor; private String testThreadFactory; private String testThreadFactoryPath; private OutputHandler outputHandler; MainActionHelper(String testName) { this.testName = testName; } MainActionHelper properties(Map props) { this.props = props; return this; } MainActionHelper addExports(Set addExports) { this.addExports = addExports; return this; } MainActionHelper addOpens(Set addOpens) { this.addOpens = addOpens; return this; } MainActionHelper addMods(Set addMods) { this.addMods = addMods; return this; } MainActionHelper classpath(SearchPath classpath) { this.classpath = classpath; return this; } MainActionHelper modulepath(SearchPath modulepath) { this.modulepath = modulepath; return this; } MainActionHelper className(String className) { this.className = className; return this; } MainActionHelper classArgs(List classArgs) { this.classArgs = classArgs; return this; } MainActionHelper timeout(int timeout) { this.timeout = timeout; return this; } MainActionHelper timeoutFactor(float timeoutFactor) { this.timeoutFactor = timeoutFactor; return this; } MainActionHelper testThreadFactory(String testThreadFactory) { this.testThreadFactory = testThreadFactory; return this; } MainActionHelper testThreadFactoryPath(String testThreadFactoryPath) { this.testThreadFactoryPath = testThreadFactoryPath; return this; } MainActionHelper outputHandler(OutputHandler outputHandler) { this.outputHandler = outputHandler; return this; } public AStatus runClass() { SaveState saved = new SaveState(); Properties p = System.getProperties(); for (Map.Entry e : props.entrySet()) { String name = e.getKey(); String value = e.getValue(); if (name.equals("test.class.path.prefix")) { SearchPath cp = new SearchPath(value, System.getProperty("java.class.path")); p.put("java.class.path", cp.toString()); } else { p.put(e.getKey(), e.getValue()); } } System.setProperties(p); PrintStream out = outputHandler.getPrintStream(OutputHandler.OutputKind.STDOUT, true); PrintStream err = outputHandler.getPrintStream(OutputHandler.OutputKind.STDERR, true); AStatus status = passed(EXEC_PASS); try { Class c; ClassLoader loader = ClassLoader.getSystemClassLoader(); if (modulepath != null && !modulepath.isEmpty()) { loader = ModuleHelper.addModules(modulepath.asList(), addMods); } if (classpath != null && !classpath.isEmpty()) { List urls = new ArrayList<>(); for (Path f : classpath.asList()) { try { urls.add(f.toUri().toURL()); } catch (MalformedURLException e) { } } loader = new URLClassLoader(urls.toArray(new URL[urls.size()]), loader); } ModuleHelper.addExports(addExports, loader); ModuleHelper.addOpens(addOpens, loader); c = loader.loadClass(className); // Select signature for main method depending on whether the class // implements the TestRunner marker interface. Class[] argTypes; String[] classArgsArray = classArgs.toArray(new String[classArgs.size()]); Object[] methodArgs; if (TestRunner.class.isAssignableFrom(c)) { // Marker interface found: use main(ClassLoader, String...) argTypes = new Class[] { ClassLoader.class, String[].class }; methodArgs = new Object[] { loader, classArgsArray }; } else { // Normal case: marker interface not found; use standard main method argTypes = new Class[] { String[].class }; methodArgs = new Object[] { classArgsArray }; } Method method = c.getMethod("main", argTypes); PrintStream realStdErr = System.err; AStatus stat = redirectOutput(out, err); if (!stat.isPassed()) { return stat; } AgentVMRunnable avmr = new AgentVMRunnable(method, methodArgs, err); // Main and Thread are same here // RUN JAVA IN ANOTHER THREADGROUP AgentVMThreadGroup tg = new AgentVMThreadGroup(err, MSG_PREFIX, timeoutFactor); Thread t; if (testThreadFactory == null) { t = new Thread(tg, avmr); } else { t = TestThreadFactoryHelper.loadThreadFactory(testThreadFactory, testThreadFactoryPath).newThread(avmr); } Alarm alarm = null; if (timeout > 0) { PrintWriter alarmOut = outputHandler.getPrintWriter(OutputHandler.OutputKind.LOG, true); alarm = Alarm.schedulePeriodicInterrupt(timeout, TimeUnit.SECONDS, alarmOut, t); } Throwable error = null; t.setName("AgentVMThread"); t.start(); try { t.join(); if (traceCleanup) { realStdErr.println("main method returned"); } } catch (InterruptedException e) { realStdErr.println("main method interrupted"); if (t.isInterrupted() && (tg.uncaughtThrowable == null)) { error = e; status = error(MAIN_THREAD_INTR + e.getMessage()); } } finally { if (traceCleanup) { realStdErr.println("cleaning threads"); } tg.cleanup(); if (traceCleanup) { realStdErr.println("thread cleanup completed"); } if (alarm != null) { alarm.cancel(); if (alarm.didFire() && error == null) { err.println("Test timed out. No timeout information is available in agentvm mode."); error = new Error("timeout"); status = error(MAIN_THREAD_TIMEOUT); } } } if (((avmr.t != null) || (tg.uncaughtThrowable != null)) && (error == null)) { if (avmr.t == null) { error = tg.uncaughtThrowable; } else { error = avmr.t; } if (SKIP_EXCEPTION.equals(error.getClass().getName())) { status = passed(MAIN_SKIPPED + error.toString()); } else { status = failed(MAIN_THREW_EXCEPT + error.toString()); } } if (status.getReason().contains("java.lang.SecurityException: System.exit() forbidden")) { status = failed(UNEXPECT_SYS_EXIT); } else if (!tg.cleanupOK) { status = error(EXEC_ERROR_CLEANUP); } } catch (ClassNotFoundException e) { e.printStackTrace(err); err.println(); err.println(MSG_PREFIX + "main() method must be in a public class named"); err.println(MSG_PREFIX + className + " in file " + className + ".java"); err.println(); status = error(MAIN_CANT_LOAD_TEST + e); } catch (NoSuchMethodException e) { e.printStackTrace(err); err.println(); err.println(MSG_PREFIX + "main() method must be in a public class named"); err.println(MSG_PREFIX + className + " in file " + className + ".java"); err.println(); status = error(MAIN_CANT_FIND_MAIN); } catch (ModuleHelper.Fault e) { if (e.getCause() != null) e.printStackTrace(err); status = error(MAIN_CANT_INIT_MODULE_EXPORTS + e.getMessage()); } finally { out.close(); err.close(); status = saved.restore(testName, status); } return status; } private static final boolean traceCleanup = Flags.get("traceCleanup"); private static final String MSG_PREFIX = "JavaTest Message: "; private static final String SKIP_EXCEPTION = "jtreg.SkippedException"; private static final String // runAgentJVM MAIN_THREAD_INTR = "Thread interrupted: ", MAIN_THREAD_TIMEOUT = "Timeout", MAIN_THREW_EXCEPT = "`main' threw exception: ", MAIN_CANT_LOAD_TEST = "Can't load test: ", MAIN_CANT_FIND_MAIN = "Can't find `main' method", MAIN_CANT_INIT_MODULE_EXPORTS = "Can't init module exports: ", MAIN_SKIPPED = "Skipped: "; /** * Marker interface for test driver classes, which need to be passed a class * loader to load the classes for the test. * * @see JUnitRunner */ public interface TestRunner { } //----------internal classes------------------------------------------------ private static class AgentVMRunnable implements Runnable { public AgentVMRunnable(Method m, Object[] args, PrintStream out) { method = m; this.args = args; this.out = out; } // SameVMRunnable() @Override public void run() { try { // RUN JAVA PROGRAM result = method.invoke(null, args); out.println(); out.println(MSG_PREFIX + "Test complete."); out.println(); } catch (InvocationTargetException e) { // main must have thrown an exception, so the test failed e.getTargetException().printStackTrace(out); t = e.getTargetException(); out.println(); out.println(MSG_PREFIX + "Test threw exception: " + t.getClass().getName()); out.println(MSG_PREFIX + "shutting down test"); out.println(); } catch (IllegalAccessException e) { e.printStackTrace(out); t = e; out.println(); out.println(MSG_PREFIX + "Verify that the class defining the test is"); out.println(MSG_PREFIX + "declared public (test invoked via reflection)"); out.println(); } } // run() //----------member variables-------------------------------------------- public Object result; private final Method method; private final Object[] args; private final PrintStream out; Throwable t = null; } static class AgentVMThreadGroup extends ThreadGroup { private double timeoutFactor; AgentVMThreadGroup(PrintStream out, String messagePrefix, double timeoutFactor) { super("AgentVMThreadGroup"); this.out = out; this.messagePrefix = messagePrefix; this.timeoutFactor = timeoutFactor; } @Override public synchronized void uncaughtException(Thread t, Throwable e) { if (e instanceof ThreadDeath) return; if ((uncaughtThrowable == null) && (!cleaning)) { uncaughtThrowable = e; uncaughtThread = t; } cleanup(); } private void cleanup() { cleaning = true; final int CLEANUP_ROUNDS = 4; // final long MAX_CLEANUP_TIME_MILLIS = 2 * 60 * 1000; final long MAX_CLEANUP_TIME_MILLIS = (long) (10 * 1000 * timeoutFactor); final long CLEANUP_MILLIS_PER_ROUND = MAX_CLEANUP_TIME_MILLIS / CLEANUP_ROUNDS; final long NANOS_PER_MILLI = 1000L * 1000L; long startCleanupTime = System.nanoTime(); for (int i = 1; i <= CLEANUP_ROUNDS; i++) { long deadline = startCleanupTime + i * CLEANUP_MILLIS_PER_ROUND * NANOS_PER_MILLI; List liveThreads = liveThreads(); if (liveThreads.isEmpty()) { // nothing left to cleanup cleanupOK = true; return; } // kick the remaining live threads for (Thread thread : liveThreads) thread.interrupt(); // try joining as many threads as possible before // the round times out for (Thread thread : liveThreads) { long millis = (deadline - System.nanoTime()) / NANOS_PER_MILLI; if (millis <= 0) break; try { thread.join(millis); } catch (InterruptedException ignore) { } } } List remaining = liveThreads(); if (remaining.isEmpty()) { // nothing left to cleanup cleanupOK = true; return; } out.println(); out.println(messagePrefix + "Problem cleaning up the following threads:"); printTraces(remaining); cleanupOK = false; } // cleanup() /** * Gets all the "interesting" threads in the thread group. * @see ThreadGroup#enumerate(Thread[]) */ private List liveThreads() { for (int estSize = activeCount() + 1; ; estSize = estSize * 2) { Thread[] threads = new Thread[estSize]; int num = enumerate(threads); if (num < threads.length) { ArrayList list = new ArrayList<>(num); for (int i = 0; i < num; i++) { Thread t = threads[i]; if (t.isAlive() && t != Thread.currentThread() && !t.isDaemon()) { list.add(t); } } return list; } } } private void printTraces(List threads) { final int MAX_FRAMES = 20; for (Thread t : threads) { out.println(t.getName()); StackTraceElement[] trace = t.getStackTrace(); for (int i = 0; i < trace.length; i++) { out.println(" at " + trace[i]); if (i == MAX_FRAMES) { out.println(" ..."); break; } } out.println(); } } //----------member variables-------------------------------------------- private final PrintStream out; private final String messagePrefix; private boolean cleaning = false; Throwable uncaughtThrowable = null; Thread uncaughtThread = null; boolean cleanupOK = false; } } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/agent/MainWrapper.java000066400000000000000000000222601461415321300303450ustar00rootroot00000000000000/* * Copyright (c) 1998, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.agent; import java.io.FileReader; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * This class is the wrapper for all main/othervm tests. */ public class MainWrapper { public static String TEST_THREAD_FACTORY = "jtreg.test.thread.factory"; public static String TEST_THREAD_FACTORY_PATH = "jtreg.test.thread.factory.path"; public static void main(String[] args) { String moduleName; String className; String[] classArgs; try { FileReader in = new FileReader(args[0]); StringBuilder sb = new StringBuilder(); char[] buf = new char[1024]; int howMany; while ((howMany = in.read(buf)) > 0) sb.append(buf, 0, howMany); in.close(); String[] fileArgs = StringArray.splitTerminator("\0", sb.toString()); int i = 0; String moduleClassName = fileArgs[i++]; int sep = moduleClassName.indexOf('/'); moduleName = (sep == -1) ? null : moduleClassName.substring(0, sep); className = (sep == -1) ? moduleClassName : moduleClassName.substring(sep + 1); classArgs = StringArray.splitWS(fileArgs[i++]); } catch (IOException e) { AStatus.failed(MAIN_CANT_READ_ARGS + e).exit(); throw new IllegalStateException(); // implies exit() didn't sucees } // RUN JAVA IN ANOTHER THREADGROUP MainThreadGroup tg = new MainThreadGroup(); Runnable task = new MainTask(moduleName, className, classArgs); Thread t; String testThreadFactory = System.getProperty(TEST_THREAD_FACTORY); String testThreadFactoryPath = System.getProperty(TEST_THREAD_FACTORY_PATH); if (testThreadFactory == null) { t = new Thread(tg, task); } else { t = TestThreadFactoryHelper.loadThreadFactory(testThreadFactory, testThreadFactoryPath).newThread(task); } t.setName("MainThread"); t.start(); try { t.join(); } catch (InterruptedException e) { AStatus.failed(MAIN_THREAD_INTR + Thread.currentThread().getName()).exit(); } // tg.cleanup(); if (tg.uncaughtThrowable != null) { handleTestException(tg.uncaughtThrowable); } else { AStatus.passed("") .exit(); } } // main() private static void handleTestException(Throwable e) { if (SKIP_EXCEPTION.equals(e.getClass().getName())) { AStatus.passed(MAIN_SKIPPED + e) .exit(); } else { AStatus.failed(MAIN_THREW_EXCEPT + e) .exit(); } } static class MainTask implements Runnable { MainTask(String moduleName, String className, String[] args) { this.moduleName = moduleName; this.className = className; this.args = args; } public void run() { try { ClassLoader cl; if (moduleName != null) { Class layerClass; try { layerClass = Class.forName("java.lang.ModuleLayer"); } catch (ClassNotFoundException e) { layerClass = Class.forName("java.lang.reflect.Layer"); } Method bootMethod = layerClass.getMethod("boot"); Object bootLayer = bootMethod.invoke(null); Method findLoaderMth = layerClass.getMethod("findLoader", String.class); cl = (ClassLoader) findLoaderMth.invoke(bootLayer, moduleName); } else { cl = getClass().getClassLoader(); } // RUN JAVA PROGRAM Class c = Class.forName(className, false, cl); Method mainMethod = c.getMethod("main", String[].class); mainMethod.invoke(null, (Object) args); } catch (InvocationTargetException e) { Throwable throwable = e.getTargetException(); throwable.printStackTrace(System.err); System.err.println(); System.err.println("JavaTest Message: Test threw exception: " + throwable); System.err.println("JavaTest Message: shutting down test"); System.err.println(); handleTestException(throwable); } catch (ClassNotFoundException e) { e.printStackTrace(System.err); System.err.println(); System.err.println("JavaTest Message: main() method must be in a public class named"); System.err.println("JavaTest Message: " + className + " in file " + className + ".java"); System.err.println(); AStatus.error(MAIN_CANT_LOAD_TEST + e).exit(); } catch (NoSuchMethodException e) { e.printStackTrace(System.err); System.err.println(); System.err.println("JavaTest Message: main() method must be in a public class named"); System.err.println("JavaTest Message: " + className + " in file " + className + ".java"); System.err.println(); AStatus.error(MAIN_CANT_FIND_MAIN).exit(); } catch (IllegalAccessException e) { e.printStackTrace(System.err); System.err.println(); System.err.println("JavaTest Message: Verify that the class defining the test is"); System.err.println("JavaTest Message: declared public (test invoked via reflection)"); System.err.println(); AStatus.error(e.toString()).exit(); } } // run private final String moduleName; private final String className; private final String[] args; } static class MainThreadGroup extends ThreadGroup { MainThreadGroup() { super("MainThreadGroup"); } // MainThreadGroup() public void uncaughtException(Thread t, Throwable e) { if (e instanceof ThreadDeath) return; e.printStackTrace(System.err); if ((uncaughtThrowable == null) && (!cleanMode)) { uncaughtThrowable = e; uncaughtThread = t; } // cleanup(); AStatus.failed(MAIN_THREW_EXCEPT + e).exit(); } // uncaughtException() // public void cleanup() { // cleanMode = true; // boolean someAlive = false; // Thread ta[] = new Thread[activeCount()]; // enumerate(ta); // for (int i = 0; i < ta.length; i++) { // if (ta[i] != null && // ta[i].isAlive() && // ta[i] != Thread.currentThread() && // !ta[i].isDaemon()) // { // ta[i].interrupt(); // someAlive = true; // //Thread.currentThread().yield(); // } // } // if (someAlive) { // Thread.currentThread().yield(); // cleanup(); // } // } // cleanup() //----------member variables-------------------------------------------- private final boolean cleanMode = false; Throwable uncaughtThrowable = null; Thread uncaughtThread = null; } //----------member variables------------------------------------------------ private static final String MAIN_CANT_READ_ARGS = "JavaTest Error: Can't read main args file.", MAIN_THREAD_INTR = "Thread interrupted: ", MAIN_THREW_EXCEPT = "`main' threw exception: ", MAIN_CANT_LOAD_TEST = "Can't load test: ", MAIN_CANT_FIND_MAIN = "Can't find `main' method", MAIN_SKIPPED = "Skipped: "; private static final String SKIP_EXCEPTION = "jtreg.SkippedException"; } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/agent/ModuleHelper.java000066400000000000000000000212451461415321300305070ustar00rootroot00000000000000/* * Copyright (c) 2015, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.agent; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.nio.file.Path; import java.util.*; public class ModuleHelper { static class Fault extends Exception { private static final long serialVersionUID = 1L; Fault(String message, Throwable t) { super(message, t); } } static void addExports(Set exports, ClassLoader loader) throws Fault { for (String e : exports) { addExportsOrOpens(e, false, loader); } } static void addOpens(Set opens, ClassLoader loader) throws Fault { for (String o : opens) { addExportsOrOpens(o, true, loader); } } static ClassLoader addModules(List libs, Set modules) throws Fault { init(); try { /* java.lang.module.ModuleFinder finder = ModuleFinder.of(paths); java.lang.module.ModuleFinder emptyFinder = ModuleFinder.of(); java.lang.module.Configuration bootConfig = bootLayer.configuration(); java.lang.module.Configuration config = bootConfig.resolve(finder, ModuleFinder.of(), modules); ModuleLayer layer = bootLayer.defineModulesWithOneLoader(configuration, ClassLoader.getSystemClassLoader()); ClassLoader result = layer.findLoader(modules.iterator().next()); */ Object finder = moduleFinderOfMethod.invoke(null, new Object[] { libs.toArray(new Path[0]) }); Object emptyFinder = moduleFinderOfMethod.invoke(null, new Object[] { new Path[0] }); Object bootConfig = configurationMethod.invoke(bootLayer); Object config = resolveMethod.invoke(bootConfig, finder, emptyFinder, modules); Object layer = defineModulesWithOneLoaderMethod.invoke(bootLayer, config, ClassLoader.getSystemClassLoader()); return (ClassLoader) findLoaderMethod.invoke(layer, modules.iterator().next()); } catch (SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { throw new Fault("unexpected exception: " + e, e); } } /* * Use reflection to simulate: * Optional opt_module = Layer.boot().findModule(moduleName); * if (!opt_module.isPresent()) * throw new Fault(); * Module module = opt_module.get(); * Module targetModule = targetLoader.getUnnamedModule(); * then one of: * JTRegModuleHelper.implAddExports(module, packageName, targetModule); * JTRegModuleHelper.implAddpens(module, packageName, targetModule); */ private static void addExportsOrOpens(String modulePackageName, boolean isOpen, ClassLoader targetLoader) throws Fault { int sep = modulePackageName.indexOf("/"); String moduleName = modulePackageName.substring(0, sep); String packageName = modulePackageName.substring(sep + 1); try { init(); /* * Optional opt_module = bootLayer.findModule(moduleName); * if (!opt_module.isPresent()) * throw new Fault(); */ Optional opt_module = (Optional) findModuleMethod.invoke(bootLayer, moduleName); if (!opt_module.isPresent()) { throw new Fault("module not found: " + moduleName, null); } /* * Module module = opt_module.get(); */ Object module = opt_module.get(); /* * Module targetModule = targetLoader.getUnnamedModule(); */ Object targetModule = getUnnamedModuleMethod.invoke(targetLoader); /* * Call one of: * JTRegModuleHelper.addExports(module, packageName, isPrivate, targetModule); * JTRegModuleHelper.addOpens(module, packageName, isPrivate, targetModule); */ try { Method m = isOpen ? addOpensMethod : addExportsMethod; m.invoke(null, module, packageName, targetModule); } catch (InvocationTargetException e) { if (e.getCause() instanceof IllegalArgumentException) { String msg = e.getCause().getMessage(); throw new Fault("package not found: " + packageName + " (" + msg + ")", null); } else { throw new Fault("unexpected exception: " + e, e); } } } catch (SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { throw new Fault("unexpected exception: " + e, e); } } private static synchronized void init() throws Fault { if (bootLayer != null) return; try { // new in Jave SE 9 Class moduleFinderClass = Class.forName("java.lang.module.ModuleFinder"); moduleFinderOfMethod = moduleFinderClass.getDeclaredMethod("of", Path[].class); Class configurationClass = Class.forName("java.lang.module.Configuration"); resolveMethod = configurationClass.getDeclaredMethod("resolve", moduleFinderClass, moduleFinderClass, Collection.class); Class layerClass = Class.forName("java.lang.ModuleLayer"); findModuleMethod = layerClass.getDeclaredMethod("findModule", String.class); configurationMethod = layerClass.getDeclaredMethod("configuration"); defineModulesWithOneLoaderMethod = layerClass.getDeclaredMethod("defineModulesWithOneLoader", configurationClass, ClassLoader.class); findLoaderMethod = layerClass.getDeclaredMethod("findLoader", String.class); Method bootLayerMethod = layerClass.getDeclaredMethod("boot"); /* * Layer bootLayer = Layer.boot(); */ bootLayer = bootLayerMethod.invoke(null); Class helperClass = Class.forName("java.lang.JTRegModuleHelper"); addExportsMethod = helperClass.getDeclaredMethod("addExports", Object.class, String.class, Object.class); addOpensMethod = helperClass.getDeclaredMethod("addOpens", Object.class, String.class, Object.class); getUnnamedModuleMethod = ClassLoader.class.getDeclaredMethod("getUnnamedModule"); } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalAccessException |IllegalArgumentException | InvocationTargetException e) { throw new Fault("unexpected exception: " + e, e); } } // on java.lang.module.Layer private static Method findModuleMethod; private static Method configurationMethod; private static Method defineModulesWithOneLoaderMethod; private static Method findLoaderMethod; private static Object bootLayer; // on java.lang.module.ModuleFinder private static Method moduleFinderOfMethod; // on java.lang.module.Configuration private static Method resolveMethod; // on java.lang.ClassLoader private static Method getUnnamedModuleMethod; // on java.lang.JTRegModuleHelper or java.lang.reflect.JTRegModuleHelper private static Method addExportsMethod; private static Method addOpensMethod; } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/agent/RegressionCompileCommand.java000066400000000000000000000227171461415321300330570ustar00rootroot00000000000000/* * Copyright (c) 1997, 2018, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.agent; import java.io.PrintWriter; import java.lang.reflect.Method; import java.lang.reflect.Modifier; // Derived from com.sun.javatest.lib.JavaCompileCommand, import static com.sun.javatest.regtest.agent.AStatus.*; // This is primarily a cut-n-paste copy of com.sun.javatest.lib.JavaCompileCommand, // that provides a way to map compiler exit codes to a status. /** * Invoke a Java compiler via reflection. * The compiler is assumed to have a constructor and compile method * matching the following signature: *
 * public class COMPILER {
 *    public static int compile(String[] args, PrintWriter out);
 * }
 * 
* The command is primarily intended for (but not limited to) the * compiler javac supplied with JDK. */ public class RegressionCompileCommand { /** * A stand-alone entry point for this command. An instance of this * command is created, and its {@code run} method invoked, * passing in the command line args and {@code System.out} and * {@code System.err} as the two streams. * @param args command line arguments for this command. * @see #run */ public static void main(String[] args) { PrintWriter out = new PrintWriter(System.out); PrintWriter err = new PrintWriter(System.err); AStatus s; try { RegressionCompileCommand c = new RegressionCompileCommand(); s = c.run(args, out, err); } finally { out.flush(); err.flush(); } s.exit(); } /** * Invoke a specified compiler, or the default, javac. * If the first word in the {@code args} array is "-compiler" * the second is interpreted as the class name for the compiler to be * invoked, optionally preceded by a name for the compiler, separated * from the class name by a colon. If no -compiler is specified, * the default is `javac:com.sun.tools.javac.Main'. If -compiler is specified * but no compiler name is given before the class name, the default name * will be `java ' followed by the classname. For example, `-compiler Main' * will result in the class name being `Main' and the compiler name being * `java Main'. After determining the class and compiler name, * an instance of the compiler class will be created, passing it a stream * using the {@code ref} parameter, and the name of the compiler. * Then the `compile' method will be invoked, passing it the remaining * values of the `args' parameter. If the compile method returns true, * the result will be a status of `passed'; if it returns `false', the * result will be `failed'. If any problems arise, the result will be * a status of `error'. * @param args An optional specification for the compiler to be invoked, * followed by arguments for the compiler's compile method. * @param log Not used. * @param ref Passed to the compiler that is invoked. * @return `passed' if the compilation is successful; `failed' if the * compiler is invoked and errors are found in the file(s) * being compiler; or `error' if some more serios problem arose * that prevented the compiler performing its task. */ public AStatus run(String[] args, PrintWriter log, PrintWriter ref) { if (args.length == 0) return error("No args supplied"); String compilerClassName = null; String compilerName = null; String[] options = null; // If we find a '-' in the args, what comes before it are // options for this class and what comes after it are args // for the compiler class. If don't find a '-', there are no // options for this class, and everything is handed off to // the compiler class for (int i = 0; i < args.length; i++) { if (args[i].equals("-")) { options = new String[i]; System.arraycopy(args, 0, options, 0, options.length); args = shift(args, i+1); break; } } if (options != null) { for (int i = 0; i < options.length; i++) { if (options[i].equals("-compiler")) { if (i + 1 == options.length) return error("No compiler specified after -compiler option"); String s = options[++i]; int colon = s.indexOf(":"); if (colon == -1) { compilerClassName = s; compilerName = "java " + s; } else { compilerClassName = s.substring(colon + 1); compilerName = s.substring(0, colon); } } else if (options[i].equals("-verbose")) verbose = true; else return error("Unrecognized option: " + options[i]); } } this.log = log; try { ClassLoader loader = null; Class compilerClass; if (compilerClassName != null) { compilerClass = getClass(loader, compilerClassName); if (compilerClass == null) return error("Cannot find compiler: " + compilerClassName); } else { compilerName = "javac"; compilerClass = getClass(loader, "com.sun.tools.javac.Main"); // JDK1.3+ if (compilerClass == null) return error("Cannot find compiler"); } loader = null; Object[] compileMethodArgs; Method compileMethod = getMethod(compilerClass, "compile", // JDK1.4+ String[].class, PrintWriter.class); if (compileMethod != null) compileMethodArgs = new Object[] { args, ref }; else { return error("Cannot find compile method for " + compilerClass.getName()); } if (!Modifier.isStatic(compileMethod.getModifiers())){ return error("compile method is not static"); } Object result; try { result = compileMethod.invoke(null, compileMethodArgs); } catch (Throwable t) { t.printStackTrace(log); return error("Error invoking compiler"); } // result might be a boolean (old javac) or an int (new javac) if (result instanceof Boolean) { return getStatus((Boolean) result); } else if (result instanceof Integer) { return getStatus((Integer) result); } else return error("Unexpected return value from compiler: " + result); } finally { log.flush(); ref.flush(); } } protected AStatus getStatus(boolean ok) { return (ok ? passed : failed); } protected AStatus getStatus(int exitCode) { return (exitCode == 0 ? passed : failed); } private Class getClass(ClassLoader loader, String name) { try { return (loader == null ? Class.forName(name) : loader.loadClass(name)); } catch (ClassNotFoundException e) { return null; } } private Method getMethod(Class c, String name, Class... argTypes) { try { return c.getMethod(name, argTypes); } catch (NoSuchMethodException e) { return null; } catch (Throwable t) { if (verbose) t.printStackTrace(log); return null; } } private static String[] shift(String[] args, int n) { String[] newArgs = new String[args.length - n]; System.arraycopy(args, n, newArgs, 0, newArgs.length); return newArgs; } public static boolean defaultVerbose = Boolean.getBoolean("javatest.JavaCompileCommand.verbose"); private boolean verbose = defaultVerbose; private PrintWriter log; private static final AStatus passed = passed("Compilation successful"); private static final AStatus failed = failed("Compilation failed"); } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/agent/RegressionSecurityManager.java000066400000000000000000000171241461415321300332660ustar00rootroot00000000000000/* * Copyright (c) 2000, 2018, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.agent; import java.security.Permission; import java.util.PropertyPermission; @SuppressWarnings("removal") // Security Manager and related APIs public class RegressionSecurityManager extends JavaTestSecurityManager { /** * Try to install a copy of this security manager, up to but not including JDK 18. * If another security manager is already installed, the install will fail; * a warning message will be written to the console if the previously installed * security manager is not a subtype of com.sun.javatest.JavaTestSecurityManager. * The install can be suppressed by setting the system property * "javatest.security.noSecurityManager" to true. */ public static void install() { String sv = System.getProperty("java.specification.version"); if (sv != null && sv.matches("[0-9]+")) { // older versions are 1.N int v = Integer.parseInt(sv); if (v >= 18) { // Do not install any security manager for JDK 18 or later; // see JEP 411: Deprecate the Security Manager for Removal return; } } try { // install our own permissive security manager, to prevent anyone else // installing a less permissive one. final String noSecurityMgr = "javatest.security.noSecurityManager"; if (Boolean.getBoolean(noSecurityMgr)) { System.err.println(); System.err.println(" ---- WARNING -----"); System.err.println(); System.err.println("JavaTest did not install its own Security Manager"); System.err.println("because the property " + noSecurityMgr + " was set."); System.err.println("This is not a fatal error, but it may affect the"); System.err.println("execution of sameJVM tests"); System.err.println(); } else System.setSecurityManager(new RegressionSecurityManager()); } catch (SecurityException e) { SecurityManager sm = System.getSecurityManager(); if (!(sm instanceof JavaTestSecurityManager)) { System.err.println(); System.err.println(" ---- WARNING -----"); System.err.println(); System.err.println("JavaTest could not install its own Security Manager"); System.err.println("because of the following exception:"); System.err.println(" " + e); System.err.println("This is not a fatal error, but it may affect the"); System.err.println("execution of sameJVM tests"); System.err.println(); } } } @Override public void checkExec(String cmd) { if (allowExec == false) { if (verbose) { System.err.println(getClass().getName() + ": subprocess creation forbidden"); new Throwable().printStackTrace(); } throw new SecurityException("Subprocess creation forbidden by JavaTest"); } } // In jdk1.1.x, calls to setErr(), setOut(), and setIn() call // System.checkIO() which checks Security.checkExec(). This // unfortunately means that we need this access when we // redirect test output during a "same JVM test". // ... However, JavaTest 3.x assumes JDK 1.4, so this is no longer an issue. // See setAllowSetIO(). If necessary, setAllowSetIO could check the java version // and delegate to this, but this is unlikely to be necessary. public boolean setAllowExec(boolean bool) { boolean prev = allowExec; allowExec = bool; return prev; } private boolean allowExec = true; // no overrides on this one; API control only @Override public void checkPermission(Permission perm) { // allow most stuff, but limit as appropriate if (perm instanceof RuntimePermission) { if (perm.getName().equals("setIO")) { if (!allowSetIO) // is this right or should we really restrict this more? super.checkPermission(new java.lang.RuntimePermission("setIO")); } else if (perm.getName().equals("exitVM")) { checkExit(0); } else if (perm.getName().equals("createSecurityManager")) { //super.checkPermission(new java.lang.RuntimePermission("createSecurityManager")); } else if (perm.getName().equals("setSecurityManager")) { if (!allowSetSecurityManager) forbid(perm); //super.checkPermission(new java.lang.RuntimePermission("setSecurityManager")); // if the security manager is changed, we have no way of tracking whether // properties get modified, so we have to assume they may propertiesModified = true; } } else if (perm instanceof PropertyPermission) { //super.checkPermission(perm); if (perm.getActions().contains("write")) { propertiesModified = true; } } } void forbid(Permission perm) throws SecurityException { if (verbose) { System.err.println(getClass().getName() + ": " + perm); Thread.dumpStack(); } throw new SecurityException("Action forbidden by jtreg: " + perm.getName()); } private boolean propertiesModified; @Override public synchronized void checkPropertiesAccess() { super.checkPropertiesAccess(); propertiesModified = true; } boolean isPropertiesModified() { return propertiesModified; } @Override public boolean setAllowPropertiesAccess(boolean b) { return super.setAllowPropertiesAccess(b); } void resetPropertiesModified() { propertiesModified = false; } public boolean setAllowSetIO(boolean bool) { boolean prev = allowSetIO; allowSetIO = bool; return prev; } private boolean allowSetIO = false; public boolean setAllowSetSecurityManager(boolean bool) { boolean prev = allowSetSecurityManager; allowSetSecurityManager = bool; return prev; } private boolean allowSetSecurityManager = false; static private boolean verbose = Boolean.getBoolean("javatest.security.verbose"); } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/agent/SearchPath.java000066400000000000000000000150361461415321300301450ustar00rootroot00000000000000/* * Copyright (c) 2010, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.agent; import java.io.File; import java.nio.file.Files; import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import java.util.regex.Pattern; /** * A search path, as in an ordered set of file system locations, * such as directories, zip files and jar files. */ public final class SearchPath { /** * Creates an empty search path. */ public SearchPath() { } /** * Creates a search path containing a series of entries. * Equivalent to {@code new Path().append(files)}. * * @param entries the entries to be included in the search path */ public SearchPath(Path... entries) { append(entries); } /** * Creates a search path containing the concatenation of a series of search paths. * Equivalent to {@code new Path().append(paths)}. * * @param paths the paths to be included in the search path */ public SearchPath(SearchPath... paths) { append(paths); } /** * Creates a search path containing the concatenation of a series of search paths. * Equivalent to {@code new Path().append(paths)}. * * @param paths the search paths to be included in the new search path * * @throws InvalidPathException if any of the paths contain invalid file paths */ public SearchPath(String... paths) throws InvalidPathException { append(paths); } /** * Appends a series of entries to this search path. * Entries that do not exist are ignored. * * @param entries the entries to be added to the path * @return the path itself */ public SearchPath append(Collection entries) { for (Path e: entries) { if (Files.exists(e)) { this.entries.add(e); } } return this; } /** * Appends a series of entries to this search path. * Entries that do not exist are ignored. * * @param entries entries to be added to the path * @return the path itself * * @throws InvalidPathException if any of the files are invalid */ public SearchPath append(Path... entries) throws InvalidPathException { for (Path e: entries) { if (Files.exists(e)) { this.entries.add(e); } } return this; } /** * Appends a series of paths to this search path. * * @param paths paths to be added to the search path * * @return the path itself */ public SearchPath append(SearchPath... paths) { for (SearchPath p: paths) { entries.addAll(p.entries); } return this; } /** * Appends a series of paths to this search path. * * @param paths paths to be added to the search path * @return the path itself * * @throws InvalidPathException if any of the paths contain invalid file paths */ public SearchPath append(String... paths) throws InvalidPathException { for (String p: paths) { for (String q: p.split(Pattern.quote(PATHSEP))) { if (q.length() > 0) { Path f = Paths.get(q); if (Files.exists(f)) { entries.add(f); } } } } return this; } /** * Removes entries from this search path. * * @param entries entries to be removed from the search path * @return the path itself */ public SearchPath removeAll(Collection entries) { this.entries.removeAll(entries); return this; } /** * Retains just specified entries on this search path. * * @param entries entries to be retained in the search path * @return the path itself * * @throws InvalidPathException if any of the entries are invalid */ public SearchPath retainAll(Collection entries) { this.entries.retainAll(entries); return this; } /** * Returns the list of entries that are currently on this search path. * * @return the entries on the search path */ public List asList() { return new ArrayList<>(entries); } /** * Checks if this search path is empty. * * @return {@code true} if this path does not have any entries on it, * and {@code false} otherwise */ public boolean isEmpty() { return entries.isEmpty(); } /** * Returns the string value of this search path. * * @return the string value of this search path */ @Override public String toString() { StringBuilder sb = new StringBuilder(); for (Path e: entries) { if (sb.length() > 0) sb.append(PATHSEP); sb.append(e); } return sb.toString(); } // For now, with only append operations, a LinkedHashSet is good enough. // If we wanted more flexible operations, it may be desirable to keep // both a list (to record the order) and a set (to help detect duplicates). private final Set entries = new LinkedHashSet<>(); private static final String PATHSEP = File.pathSeparator; } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/agent/StringArray.java000066400000000000000000000140661461415321300303720ustar00rootroot00000000000000/* * Copyright (c) 1998, 2016, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.agent; import java.util.ArrayList; import java.util.List; /** * Various static methods used to operate on arrays of strings. This includes * an append method and several methods to split strings based on separators, * terminators, whitespace, etc. * Limited to -target 1.1, so no generics. */ public class StringArray { /** * Splits a string based on location of "=". Always returns an array of size * 2. The first element is the stuff to the left of the "=" sign. The * second element is the stuff to the right. Assumes no spaces around the * "=". They will be part of the appropriate element in the array. Useful * separating variable assignments of the form "foo=bar". * * @param s The string to split. * @return An array of length 2, the first element contains characters * to the left of "=", the second element contains characters to * the right of the "=". Whitespace not stripped. */ public static String[] splitEqual(String s) { String[] retVal = new String[2]; int pos = s.indexOf("="); if (pos == -1) { retVal[0] = s; retVal[1] = null; } else { retVal[0] = s.substring(0, pos); retVal[1] = s.substring(pos+1); } return retVal; } // splitEqual() /** * Splits a string based on presence of a specified separator. Returns an * array of arbitrary length. The end of each element in the array is * indicated by the separator or the end of the string. If there is a * separator immediately before the end of the string, the final element * will be empty. None of the strings will contain the separator. Useful * when separating strings such as "foo/bar/bas" using separator '/'. * * @param sep The separator. * @param s The string to split. * @return An array of strings. Each string in the array is determined * by the location of the provided sep in the original string, * s. Whitespace not stripped. * @see #splitTerminator */ public static String[] splitSeparator(String sep, String s) { List v = new ArrayList<>(); int tokenStart = 0; int tokenEnd; while ((tokenEnd = s.indexOf(sep, tokenStart)) != -1) { v.add(s.substring(tokenStart, tokenEnd)); tokenStart = tokenEnd+1; } v.add(s.substring(tokenStart)); return v.toArray(new String[0]); } // splitSeparator() /** * Splits a string based on the presence of a specified terminator. Returns * an array of arbitrary length. The end of each element in the array is * indicated by the terminator. None of the strings will contain the * terminator. Useful when separating string such as "int foo; int bar;" * using terminator ';'. * * @param sep The separator. * @param s The string to split. * @return An array of strings. Each string in the array is determined * by the location of the provided sep in the original string, * s. Whitespace not stripped. * @see #splitSeparator */ public static String[] splitTerminator(String sep, String s) { List v = new ArrayList<>(); int tokenStart = 0; int tokenEnd; while ((tokenEnd = s.indexOf(sep, tokenStart)) != -1) { v.add(s.substring(tokenStart, tokenEnd)); tokenStart = tokenEnd+1; } return v.toArray(new String[0]); } // splitTerminator() /** * Splits a string according to whitespace in the string. Returns an array * of arbitrary length. Elements are delimited (start or end) by an * arbitrary number of Character.isWhitespace(). The whitespace characters * are removed. * * @param s The string to split. * @return An array of strings. Each string in the array is determined * by the presence of Character.isWhitespace(). */ public static String[] splitWS(String s) { if (s == null) return new String[0]; List v = new ArrayList<>(); int tokenStart = 0; int tokenEnd; while (true) { if (tokenStart == s.length()) break; while ((tokenStart < s.length()) && Character.isWhitespace(s.charAt(tokenStart))) tokenStart++; if (tokenStart == s.length()) break; tokenEnd = tokenStart; while ((tokenEnd < s.length()) && !Character.isWhitespace(s.charAt(tokenEnd))) tokenEnd++; v.add(s.substring(tokenStart, tokenEnd)); tokenStart = tokenEnd; } return v.toArray(new String[0]); } // splitWS() } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/agent/TestNGRunner.java000066400000000000000000000233111461415321300304540ustar00rootroot00000000000000/* * Copyright (c) 2012, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.agent; import java.io.File; import java.io.PrintWriter; import java.io.StringWriter; import java.lang.reflect.Method; import java.util.List; import java.util.stream.Collectors; import org.testng.IConfigurationListener; import org.testng.IMethodInstance; import org.testng.IMethodInterceptor; import org.testng.ITestContext; import org.testng.ITestListener; import org.testng.ITestNGListener; import org.testng.ITestResult; import org.testng.SkipException; import org.testng.TestNG; import org.testng.TestNGException; import org.testng.reporters.XMLReporter; import static org.testng.ITestResult.FAILURE; import static org.testng.ITestResult.SKIP; import static org.testng.ITestResult.SUCCESS; import static org.testng.ITestResult.SUCCESS_PERCENTAGE_FAILURE; /** * TestRunner to run TestNG tests. */ public class TestNGRunner implements MainActionHelper.TestRunner { public static void main(String... args) throws Exception { main(null, args); } public static void main(ClassLoader loader, String... args) throws Exception { if (args.length != 3) { throw new Error("wrong number of arguments"); } String testName = args[0]; boolean mixedMode = Boolean.parseBoolean(args[1]); String moduleClassName = args[2]; int sep = moduleClassName.indexOf('/'); String moduleName = (sep == -1) ? null : moduleClassName.substring(0, sep); String className = (sep == -1) ? moduleClassName : moduleClassName.substring(sep + 1); //Class mainClass = (loader == null) ? Class.forName(className) : loader.loadClass(className); ClassLoader cl; if (moduleName != null) { Class layerClass; try { layerClass = Class.forName("java.lang.ModuleLayer"); } catch (ClassNotFoundException e) { layerClass = Class.forName("java.lang.reflect.Layer"); } Method bootMethod = layerClass.getMethod("boot"); Object bootLayer = bootMethod.invoke(null); Method findLoaderMth = layerClass.getMethod("findLoader", String.class); cl = (ClassLoader) findLoaderMth.invoke(bootLayer, moduleName); } else if (loader != null) { cl = loader; } else { cl = TestNGRunner.class.getClassLoader(); } Class mainClass = Class.forName(className, false, cl); String testQuery = System.getProperty("test.query"); RegressionListener listener = new RegressionListener(); TestNG testng = new TestNG(false); testng.setMixed(mixedMode); testng.setDefaultSuiteName(testName); testng.setTestClasses(new Class[]{mainClass}); if (testQuery != null) { testng.setMethodInterceptor(new FilterMethods(className, testQuery)); } testng.addListener((ITestNGListener) listener); // recognizes both ITestListener and IConfigurationListener testng.addListener(new XMLReporter()); testng.setOutputDirectory(new File(".").getPath()); // current dir, i.e. scratch dir testng.run(); if (listener.configFailureCount > 0 || listener.failureCount > 0) { throw new Exception("failures: " + listener.failureCount); } } public static class RegressionListener implements ITestListener, IConfigurationListener { enum InfoKind { CONFIG, TEST } @Override public void onTestStart(ITestResult itr) { count++; // report(itr); } @Override public void onTestSuccess(ITestResult itr) { successCount++; report(InfoKind.TEST, itr); } @Override public void onTestFailure(ITestResult itr) { failureCount++; report(InfoKind.TEST, itr); } @Override public void onTestSkipped(ITestResult itr) { Throwable t = itr.getThrowable(); if (t != null && !(t instanceof SkipException)) { onTestFailure(itr); return; } skippedCount++; report(InfoKind.TEST, itr); } @Override public void onTestFailedButWithinSuccessPercentage(ITestResult itr) { failedButWithinSuccessPercentageCount++; report(InfoKind.TEST, itr); } @Override public void onStart(ITestContext itc) { } @Override public void onFinish(ITestContext itc) { } @Override public void onConfigurationSuccess(ITestResult itr) { configSuccessCount++; report(InfoKind.CONFIG, itr); } @Override public void onConfigurationFailure(ITestResult itr) { configFailureCount++; report(InfoKind.CONFIG, itr); } @Override public void onConfigurationSkip(ITestResult itr) { configSkippedCount++; report(InfoKind.CONFIG, itr); } void report(InfoKind k, ITestResult itr) { Throwable t = itr.getThrowable(); String suffix; if (t != null && itr.getStatus() != SUCCESS) { // combine in stack trace so we can issue single println // threading may otherwise result in interleaved output StringWriter trace = new StringWriter(); try (PrintWriter pw = new PrintWriter(trace)) { t.printStackTrace(pw); } suffix = "\n" + trace; } else { suffix = "\n"; } System.out.print(k.toString().toLowerCase() + " " + itr.getMethod().getConstructorOrMethod().getDeclaringClass().getName() + "." + itr.getMethod().getMethodName() + formatParams(itr) + ": " + statusToString(itr.getStatus()) + suffix); } private String formatParams(ITestResult itr) { StringBuilder sb = new StringBuilder(80); sb.append('('); String sep = ""; for(Object arg : itr.getParameters()) { sb.append(sep); formatParam(sb, arg); sep = ", "; } sb.append(")"); return sb.toString(); } private void formatParam(StringBuilder sb, Object param) { if (param instanceof String) { sb.append('"'); sb.append((String) param); sb.append('"'); } else { String value = String.valueOf(param); if (value.length() > 30) { sb.append(param.getClass().getName()); sb.append('@'); sb.append(Integer.toHexString(System.identityHashCode(param))); } else { sb.append(value); } } } private String statusToString(int s) { switch (s) { case SUCCESS: return "success"; case FAILURE: return "failure"; case SKIP: return "skip"; case SUCCESS_PERCENTAGE_FAILURE: return "success_percentage_failure"; default: return "??"; } } int count; int successCount; int failureCount; int skippedCount; int configSuccessCount; int configFailureCount; int configSkippedCount; int failedButWithinSuccessPercentageCount; } private static class FilterMethods implements IMethodInterceptor { private final String testClass; private final String testQuery; public FilterMethods(String testClass, String testQuery) { this.testClass = testClass; this.testQuery = testQuery; } @Override public List intercept(List ms, ITestContext c) { List result = ms.stream() .filter(mi -> testQuery.equals(mi.getMethod() .getMethodName())) .collect(Collectors.toList()); if (result.isEmpty()) { throw new TestNGException("Could not find method with name [" + testQuery + "] in class [" + testClass + "]"); } return result; } } } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/agent/TestThreadFactoryHelper.java000066400000000000000000000067601461415321300326660ustar00rootroot00000000000000/* * Copyright (c) 2022, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.agent; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ThreadFactory; /** * A class which loads thread factory for threads used to run test by jtreg. * By default, jtreg creates a new thread for each test using {@code new Thread(ThreadGroup tg, Runnable task);}, * but this may be overridden by providing an implementation of {@link java.util.concurrent.ThreadFactory}, * which might provide user-defined threads for test execution. * Please note, that additional threads started by tests don't use this factory and remain the same. *

* Example: *

 * new Thread(() -> { ....; task.run(); ....; });
 * or
 * new VirtualThread(task);
 * 
* Implementation may be specified on the {@code jtreg} command line * using {@code -testThreadFactory} and {@code -testThreadFactoryPath} arguments. * It is executed by tested JDK in {@code agentvm} and {@code othervm} modes. */ public final class TestThreadFactoryHelper { static ThreadFactory loadThreadFactory(String className, String path) { List urls = new ArrayList<>(); if (path != null) { SearchPath classpath = new SearchPath(path); for (Path f : classpath.asList()) { try { urls.add(f.toUri().toURL()); } catch (MalformedURLException e) { throw new RuntimeException(e); } } } try (URLClassLoader loader = new URLClassLoader(urls.toArray(new URL[]{}), ClassLoader.getSystemClassLoader())) { Class clz = loader.loadClass(className).asSubclass(ThreadFactory.class); Constructor ctor = clz.getDeclaredConstructor(); ThreadFactory factory = ctor.newInstance(); return factory; } catch (ClassNotFoundException | InvocationTargetException | NoSuchMethodException | InstantiationException | IllegalAccessException | IOException e) { throw new RuntimeException(e); } } } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/agent/package-info.java000066400000000000000000000043401461415321300304430ustar00rootroot00000000000000/* * Copyright (c) 2016, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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. */ /** * Provides support classes for the JDK Regression Test Harness, jtreg, * that run in the test VM. * *

Note: * All classes in this package should be compiled such that they can * be executed on the oldest supported release. This implies that the * classes may not use language features that are only available on * releases that are newer than the oldest supported release. *

Currently, {@code jtreg} supports running tests as far back as * JDK 1.2 using "othervm" mode, which means that certain classes * are restricted to be compiled with "{@code javac -target 1.2}". * It also supports running tests in "agentvm" mode as far back as * JDK 1,5, which means that the majority of classes in this package * are restricted to be compiled with "{@code javac -target 1.5}". * *

This is NOT part of any supported API. * If you write code that depends on this, you do so at your own risk. * This code and its internal interfaces are subject to change or * deletion without notice. */ package com.sun.javatest.regtest.agent; jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/config/000077500000000000000000000000001461415321300254225ustar00rootroot00000000000000jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/config/CachingTestFilter.java000066400000000000000000000101061461415321300316250ustar00rootroot00000000000000/* * Copyright (c) 2011, 2018, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.config; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; import com.sun.javatest.TestDescription; import com.sun.javatest.TestFilter; /** * A test filter that caches its results. */ public abstract class CachingTestFilter extends TestFilter { private final String name; private final String description; private final String reason; public class Entry { public final TestDescription td; public final Boolean value; Entry(TestDescription td, Boolean v) { this.td = td; this.value = v; } } private final Map cache = new HashMap<>(); /** * Creates a CachingTestFilter. * * @param name the name of this filter * @param description a description of this filter * @param reason the reason to give when not accepting a test */ CachingTestFilter(String name, String description, String reason) { this.name = name; this.description = description; this.reason = reason; } /** * Returns the cache key to use for a test description. * * @param td the test description * @return the key to use when looking up values in the cache */ protected abstract String getCacheKey(TestDescription td); /** * Returns the value to be used as the result the {@code accept} method. * * @param td the test description * @return the value * @throws Fault if any error occurred in the filter */ protected abstract boolean getCacheableValue(TestDescription td) throws Fault; /** * Returns the unmodifiable collection of entries in the cache. * @return the entries */ public Collection getCacheEntries() { return Collections.unmodifiableCollection(cache.values()); } /** * Clears all entries from the cache. */ public void clear() { cache.clear(); } @Override public String getName() { return name; } @Override public String getDescription() { return description; } @Override public String getReason() { return reason; } /** * Returns whether or not this filter accepts a test description. * * If there is not already a value for the test description in the cache, * the value will be determined by calling {@code getCacheableValue}. * * @param td the test description * @return whether or not this filter accepts the test description * @throws Fault if an error occurs. */ @Override public final boolean accepts(TestDescription td) throws Fault { String key = getCacheKey(td); Entry e = cache.get(key); if (e == null) { cache.put(key, e = new Entry(td, getCacheableValue(td))); } return e.value; } } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/config/ExecMode.java000066400000000000000000000030161461415321300277560ustar00rootroot00000000000000/* * Copyright (c) 2010, 2018, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.config; public enum ExecMode { OTHERVM, AGENTVM; static ExecMode fromString(String s) { if (s == null) return null; for (ExecMode m: values()) { if (m.toString().equalsIgnoreCase(s)) return m; } return null; } } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/config/Expr.java000066400000000000000000000655411461415321300272160ustar00rootroot00000000000000/* * Copyright (c) 2002, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.config; import static com.sun.javatest.regtest.config.Expr.Token.*; /** * Class to support simple expressions for @requires. */ public abstract class Expr { public static class Fault extends Exception { private static final long serialVersionUID = 1L; Fault(String msg) { super(msg); } } public interface Context { boolean isValidName(String name); String get(String name) throws Fault; } public static Expr parse(String s, Context c) throws Fault { Parser p = new Parser(s, c); return p.parse(); } public abstract String eval(Context c) throws Fault; public boolean evalBoolean(Context c) throws Fault { String s = eval(c); if (s.equals("true")) { return true; } else if (s.equals("false")) { return false; } else { throw new Fault("invalid boolean value: `" + s + "' for expression `" + this + "'"); } } public long evalNumber(Context c) throws Fault { String s = eval(c); try { return Long.parseLong(s); } catch (NumberFormatException ex) { throw new Fault("invalid numeric value: " + s); } } abstract int precedence(); Expr order() { return this; } static class Parser { Parser(String text, Context context) throws Fault { this.context = context; this.text = text; nextToken(); } Expr parse() throws Fault { Expr e = parseExpr(); expect(END); return e; } Expr parseExpr() throws Fault { for (Expr e = parseTerm(); e != null; e = e.order()) { switch (token) { case ADD: nextToken(); e = new AddExpr(e, parseTerm()); break; case AND: nextToken(); e = new AndExpr(e, parseTerm()); break; case DIV: nextToken(); e = new DivideExpr(e, parseTerm()); break; case EQ: nextToken(); e = new EqualExpr(e, parseTerm()); break; case GE: nextToken(); e = new GreaterEqualExpr(e, parseTerm()); break; case GT: nextToken(); e = new GreaterExpr(e, parseTerm()); break; case LE: nextToken(); e = new LessEqualExpr(e, parseTerm()); break; case LT: nextToken(); e = new LessExpr(e, parseTerm()); break; case MATCH: nextToken(); e = new MatchExpr(e, parseTerm()); break; case MUL: nextToken(); e = new MultiplyExpr(e, parseTerm()); break; case NE: nextToken(); e = new NotEqualExpr(e, parseTerm()); break; case OR: nextToken(); e = new OrExpr(e, parseTerm()); break; case REM: nextToken(); e = new RemainderExpr(e, parseTerm()); break; case SUB: nextToken(); e = new SubtractExpr(e, parseTerm()); break; default: return e; } } // bogus return to keep compiler happy return null; } Expr parseTerm() throws Fault { switch (token) { case NAME: String id = idValue; nextToken(); if (context.isValidName(id)) return new NameExpr(id); else throw new Fault("invalid name: " + id); case NOT: nextToken(); return new NotExpr(parseTerm()); case NUMBER: case TRUE: case FALSE: String num = idValue; nextToken(); return new NumberExpr(num); case LPAREN: nextToken(); Expr e = parseExpr(); expect(RPAREN); return new ParenExpr(e); case STRING: String s = idValue; nextToken(); return new StringExpr(s); default: throw new Fault(token.getText() + " not expected"); } } private void expect(Token t) throws Fault { if (t == token) { nextToken(); } else { throw new Fault(t.getText() + "expected, but " + token.getText() + " found"); } } private void nextToken() throws Fault { while (index < text.length()) { char c = text.charAt(index++); switch (c) { case ' ': case '\t': continue; case '&': token = AND; return; case '|': token = OR; return; case '+': token = ADD; return; case '-': token = SUB; return; case '*': token = MUL; return; case '/': token = DIV; return; case '%': token = REM; return; case '(': token = LPAREN; return; case ')': token = RPAREN; return; case '<': if (index < text.length() && text.charAt(index) == '=') { token = LE; index++; } else { token = LT; } return; case '>': if (index < text.length() && text.charAt(index) == '=') { token = GE; index++; } else { token = GT; } return; case '~': if (index < text.length() && text.charAt(index) == '=') { token = MATCH; index++; } else { throw new Fault("unexpected character after `~'"); } return; case '=': if (index < text.length() && text.charAt(index) == '=') { token = EQ; index++; } else { throw new Fault("unexpected character after `='"); } return; case '!': if (index < text.length() && text.charAt(index) == '=') { token = NE; index++; } else { token = NOT; } return; case '\"': StringBuilder sb = new StringBuilder(); if (index < text.length()) { c = text.charAt(index); index++; } else { throw new Fault("invalid string constant"); } while (c != '\"') { if (c == '\\') { if (index < text.length()) { c = text.charAt(index); index++; } else { throw new Fault("invalid string constant"); } switch (c) { // standard Java escapes; no Unicode (for now) case 'b': c = '\b'; break; case 'f': c = '\f'; break; case 'n': c = '\n'; break; case 'r': c = '\r'; break; case 't': c = '\t'; break; case '\\': c = '\\'; break; case '\'': c = '\''; break; case '\"': c = '\"'; break; default: throw new Fault("invalid string constant"); } } sb.append(c); if (index < text.length()) { c = text.charAt(index); index++; } else { break; } } if (c == '\"') { token = STRING; idValue = String.valueOf(sb); } else { throw new Fault("invalid string constant"); } return; default: if (Character.isUnicodeIdentifierStart(c)) { idValue = String.valueOf(c); while (index < text.length()) { c = text.charAt(index); if (Character.isUnicodeIdentifierPart(c) || c == '.') { if (!Character.isIdentifierIgnorable(c)) { idValue += c; } index++; } else { break; } } if (idValue.equalsIgnoreCase("true")) { token = TRUE; } else if (idValue.equalsIgnoreCase("false")) { token = FALSE; } else { token = NAME; } return; } else if (Character.isDigit(c)) { int start = index - 1; while (index < text.length()) { c = text.charAt(index); if (Character.isDigit(c)) { index++; } else { switch (c) { case 'k': case 'K': case 'm': case 'M': case 'g': case 'G': index++; } break; } } token = NUMBER; idValue = text.substring(start, index); return; } else { throw new Fault("unrecognized character: `" + c + "'"); } } } token = END; } private final Context context; private final String text; private int index; private Token token; private String idValue; } enum Token { ADD("+"), AND("&"), DIV("/"), END(""), ERROR(""), EQ("="), FALSE("false"), GE(">="), GT(">"), LE("<="), LPAREN("("), LT("<"), MATCH("~="), MUL("*"), NAME(""), NE("!="), NOT("!"), NUMBER(""), OR("|"), REM("%"), RPAREN(")"), STRING(""), SUB("-"), TRUE("true"); Token(String text) { this.text = text; } String getText() { return text.startsWith("<") ? text : "'" + text + "'"; } final String text; } protected static final int PREC_LIT = 6; protected static final int PREC_NOT = 6; protected static final int PREC_NUM = 6; protected static final int PREC_PRN = 6; protected static final int PREC_TRM = 6; protected static final int PREC_DIV = 5; protected static final int PREC_MUL = 5; protected static final int PREC_REM = 5; protected static final int PREC_ADD = 4; protected static final int PREC_SUB = 4; protected static final int PREC_GE = 3; protected static final int PREC_GT = 3; protected static final int PREC_LE = 3; protected static final int PREC_LT = 3; protected static final int PREC_EQ = 2; protected static final int PREC_NE = 2; protected static final int PREC_AND = 1; protected static final int PREC_OR = 0; //-------------------------------------------------------------------------- abstract static class BinaryExpr extends Expr { BinaryExpr(Expr left, Expr right) { this.left = left; this.right = right; } @Override Expr order() { if (precedence() > left.precedence() && left instanceof BinaryExpr) { BinaryExpr e = (BinaryExpr) left; left = e.right; e.right = order(); return e; } else { return this; } } protected Expr left; protected Expr right; } //-------------------------------------------------------------------------- static class AddExpr extends BinaryExpr { AddExpr(Expr left, Expr right) { super(left, right); } public String eval(Context c) throws Fault { return String.valueOf(left.evalNumber(c) + right.evalNumber(c)); } int precedence() { return PREC_ADD; } @Override public String toString() { return "`" + left + "+" + right + "'"; } } //-------------------------------------------------------------------------- static class AndExpr extends BinaryExpr { AndExpr(Expr left, Expr right) { super(left, right); } public String eval(Context c) throws Fault { return String.valueOf(left.evalBoolean(c) && right.evalBoolean(c)); } int precedence() { return PREC_AND; } @Override public String toString() { return "`" + left + "&" + right + "'"; } } //-------------------------------------------------------------------------- static class DivideExpr extends BinaryExpr { DivideExpr(Expr left, Expr right) { super(left, right); } public String eval(Context c) throws Fault { return String.valueOf(left.evalNumber(c) / right.evalNumber(c)); } int precedence() { return PREC_DIV; } @Override public String toString() { return "`" + left + "/" + right + "'"; } } //-------------------------------------------------------------------------- static class EqualExpr extends BinaryExpr { EqualExpr(Expr left, Expr right) { super(left, right); } public String eval(Context c) throws Fault { return String.valueOf(left.eval(c).equalsIgnoreCase(right.eval(c))); } int precedence() { return PREC_EQ; } @Override public String toString() { return "`" + left + "==" + right + "'"; } } //-------------------------------------------------------------------------- static class GreaterExpr extends BinaryExpr { GreaterExpr(Expr left, Expr right) { super(left, right); } public String eval(Context c) throws Fault { return String.valueOf(left.evalNumber(c) > right.evalNumber(c)); } int precedence() { return PREC_GT; } @Override public String toString() { return "`" + left + ">" + right + "'"; } } //-------------------------------------------------------------------------- static class GreaterEqualExpr extends BinaryExpr { GreaterEqualExpr(Expr left, Expr right) { super(left, right); } public String eval(Context c) throws Fault { return String.valueOf(left.evalNumber(c) >= right.evalNumber(c)); } int precedence() { return PREC_GE; } @Override public String toString() { return "`" + left + ">=" + right + "'"; } } //-------------------------------------------------------------------------- static class LessExpr extends BinaryExpr { LessExpr(Expr left, Expr right) { super(left, right); } public String eval(Context c) throws Fault { return String.valueOf(left.evalNumber(c) < right.evalNumber(c)); } int precedence() { return PREC_LT; } @Override public String toString() { return "`" + left + "<" + right + "'"; } } //-------------------------------------------------------------------------- static class LessEqualExpr extends BinaryExpr { LessEqualExpr(Expr left, Expr right) { super(left, right); } public String eval(Context c) throws Fault { return String.valueOf(left.evalNumber(c) <= right.evalNumber(c)); } int precedence() { return PREC_LE; } @Override public String toString() { return "`" + left + "<=" + right + "'"; } } //-------------------------------------------------------------------------- static class MatchExpr extends BinaryExpr { MatchExpr(Expr left, Expr right) { super(left, right); } public String eval(Context c) throws Fault { return String.valueOf(left.eval(c).matches(right.eval(c))); } int precedence() { return PREC_EQ; } @Override public String toString() { return "`" + left + "~=" + right + "'"; } } //-------------------------------------------------------------------------- static class MultiplyExpr extends BinaryExpr { MultiplyExpr(Expr left, Expr right) { super(left, right); } public String eval(Context c) throws Fault { return String.valueOf(left.evalNumber(c) * right.evalNumber(c)); } int precedence() { return PREC_MUL; } @Override public String toString() { return "`" + left + "*" + right + "'"; } } //-------------------------------------------------------------------------- static class NameExpr extends Expr { NameExpr(String name) { this.name = name; } public String eval(Context c) throws Fault { String v = c.get(name); if (v == null) throw new Fault("name not defined: " + name); return v; } int precedence() { return PREC_TRM; } @Override public String toString() { return name; } private final String name; } //-------------------------------------------------------------------------- static class NotEqualExpr extends BinaryExpr { NotEqualExpr(Expr left, Expr right) { super(left, right); } public String eval(Context c) throws Fault { return String.valueOf(!left.eval(c).equalsIgnoreCase(right.eval(c))); } int precedence() { return PREC_NE; } @Override public String toString() { return "`" + left + "!=" + right + "'"; } } //-------------------------------------------------------------------------- static class NotExpr extends Expr { NotExpr(Expr expr) { this.expr = expr; } public String eval(Context c) throws Fault { return String.valueOf(!expr.evalBoolean(c)); } int precedence() { return PREC_NOT; } @Override public String toString() { return "!" + expr; } private final Expr expr; } //-------------------------------------------------------------------------- static class NumberExpr extends Expr { NumberExpr(String value) { this.value = value; } public String eval(Context c) throws Fault { long scale; char lastCh = value.charAt(value.length() -1); switch (lastCh) { case 'k': case 'K': scale = 1024; break; case 'm': case 'M': scale = 1024 * 1024; break; case 'g': case 'G': scale = 1024 * 1024 * 1024; break; default: return value; } try { String s = value.substring(0, value.length() - 1); return String.valueOf(Long.parseLong(s) * scale); } catch (NumberFormatException ex) { throw new Fault("invalid numeric value: " + value); } } int precedence() { return PREC_NUM; } @Override public String toString() { return value; } private final String value; } //-------------------------------------------------------------------------- static class OrExpr extends BinaryExpr { OrExpr(Expr left, Expr right) { super(left, right); } public String eval(Context c) throws Fault { return String.valueOf(left.evalBoolean(c) || right.evalBoolean(c)); } int precedence() { return PREC_OR; } @Override public String toString() { return "`" + left + "|" + right + "'"; } } //-------------------------------------------------------------------------- static class ParenExpr extends Expr { ParenExpr(Expr expr) { this.expr = expr; } public String eval(Context c) throws Fault { return expr.eval(c); } int precedence() { return PREC_PRN; } @Override public String toString() { return "(" + expr + ")"; } private final Expr expr; } //-------------------------------------------------------------------------- static class RemainderExpr extends BinaryExpr { RemainderExpr(Expr left, Expr right) { super(left, right); } public String eval(Context c) throws Fault { return String.valueOf(left.evalNumber(c) % right.evalNumber(c)); } int precedence() { return PREC_REM; } @Override public String toString() { return "`" + left + "%" + right + "'"; } } //-------------------------------------------------------------------------- static class StringExpr extends Expr { StringExpr(String value) { this.value = value; } public String eval(Context c) throws Fault { return value; } int precedence() { return PREC_LIT; } @Override public String toString() { return '"' + value + '"'; } private final String value; } //-------------------------------------------------------------------------- static class SubtractExpr extends BinaryExpr { SubtractExpr(Expr left, Expr right) { super(left, right); } public String eval(Context c) throws Fault { return String.valueOf(left.evalNumber(c) - right.evalNumber(c)); } int precedence() { return PREC_SUB; } @Override public String toString() { return "`" + left + "-" + right + "'"; } } } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/config/ExtraPropDefns.java000066400000000000000000000315371461415321300312020ustar00rootroot00000000000000/* * 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 * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.config; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.sun.javatest.regtest.agent.SearchPath; import com.sun.javatest.regtest.util.FileUtils; /** * Handle "extra property definitions" for @requires clauses. * By default, jtreg primarily collects the system properties, for use with @requires. * This class provides an extension mechanism to detect and provide additional characteristics * of the test JDK. */ public class ExtraPropDefns { /** * Used to report problems that are found. */ static class Fault extends Exception { private static final long serialVersionUID = 1L; Fault(String msg) { super(msg); } Fault(String msg, Throwable cause) { super(msg, cause); } } /** * Source files for classes to call to get property definitions. * All files must be java source files, containing a public class that * implements {@code Callable}. * A file may be marked as "optional" by enclosing the name in '[' ... ']'. * No error will be reported if such a file does not exist. */ private final List files; /** * Source files for additional classes to be put on the application class path. * A directory may be given, which will be expanded to all the java source files * it contains (including in subdirectories). * A file or directory may be marked as "optional" by enclosing the name in '[' ... ']'. * No error will be reported if such an item does not exist. */ private final List libs; /** * Source files for additional classes to be put on the application boot class path. * A directory may be given, which will be expanded to all the java source files * it contains (including in subdirectories). * A file or directory may be marked as "optional" by enclosing the name in '[' ... ']'. * No error will be reported if such an item does not exist. */ private final List bootLibs; /** * Additional javac options to be specified when compiling the classes to get the * values of the extra properties. */ private final List javacOpts; /** * Additional VM options to be specified when running the classes to get the * values of the extra properties. */ private final List vmOpts; /** * A stream for logging messages. */ private final PrintStream log; /** * The directory used to store classes to be put on the application class path. */ private Path classDir; /** * The directory used to store classes to be put on the application boot class path. */ private Path bootClassDir; /** * The list of names of classes to be called, to get extra properties. */ private List classes; private static final boolean trace = Boolean.getBoolean("trace.extraPropDefns"); ExtraPropDefns() { this(null, null, null, null, null); } ExtraPropDefns(String classes, String libs, String bootLibs, String javacOpts, String vmOpts) { this.files = asList(classes); this.libs = asList(libs); this.bootLibs = asList(bootLibs); this.javacOpts = asList(javacOpts); this.vmOpts = asList(vmOpts); log = System.err; } void compile(RegressionParameters params, JDK jdk, File outDir) throws Fault { compile(params, jdk, outDir.toPath()); } void compile(RegressionParameters params, JDK jdk, Path outDir) throws Fault { Path baseDir = params.getTestSuite().getRootDir().toPath(); classDir = outDir.resolve("classes"); bootClassDir = outDir.resolve("bootClasses"); compile(jdk, bootClassDir, new SearchPath(), baseDir, bootLibs, true); compile(jdk, classDir, new SearchPath(bootClassDir), baseDir, libs, true); classes = compile(jdk, classDir, new SearchPath(bootClassDir), baseDir, files, false); } Path getClassDir() { return classDir; } Path getBootClassDir() { return bootClassDir; } List getClasses() { return classes; } List getVMOpts() { return vmOpts; } private List compile(JDK jdk, Path classDir, SearchPath classpath, Path srcDir, List files, boolean allowDirs) throws Fault { if (files.isEmpty()) return Collections.emptyList(); List classNames = new ArrayList<>(); List javacArgs = new ArrayList<>(); javacArgs.add("-d"); javacArgs.add(classDir.toString()); try { // ensure classDir exists before creating the search path for -classpath Files.createDirectories(classDir); } catch (IOException e) { throw new Fault("cannot create classes directory", e); } // no need to differentiate -classpath and -Xbootclasspath/a: at compile time javacArgs.add("-classpath"); javacArgs.add(new SearchPath(classDir).append(classpath).toString()); javacArgs.addAll(javacOpts); List needCompileReasons = new ArrayList<>(); for (String e: files) { boolean optional; if (e.startsWith("[") && e.endsWith("]")) { optional = true; e = e.substring(1, e.length() - 1); } else { optional = false; } Path f = srcDir.resolve(e); if (!Files.exists(f)) { if (!optional) { System.err.println("Cannot find file " + e + " for extra property definitions"); } continue; } for (Path sf: expandJavaFiles(f, allowDirs)) { javacArgs.add(sf.toString()); String cn = getClassNameFromFile(sf); classNames.add(cn); if (needCompileReasons.isEmpty() || trace) { Path cf = classDir.resolve(cn.replace(".", File.separator) + ".class"); if (Files.exists(cf)) { if (FileUtils.compareLastModifiedTimes(sf, cf) > 0) { needCompileReasons.add("Class file is out of date; class file: " + cf + ", source file: " + sf); } } else { needCompileReasons.add("Class file not found; class file: " + cf + ", source file: " + sf); } } } } if (!needCompileReasons.isEmpty()) { if (trace) { PrintStream out = System.err; out.println("Compiling extra property definition files: " + javacArgs); needCompileReasons.forEach(out::println); } List pArgs = new ArrayList<>(); pArgs.add(jdk.getJavacProg().toString()); pArgs.addAll(javacArgs); try { Process p = new ProcessBuilder(pArgs) .redirectErrorStream(true) .start(); // pass through any output from the compiler try (BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()))) { String line; while ((line = in.readLine()) != null) { log.println(line); } } int rc = p.waitFor(); if (rc != 0) { throw new Fault("Compilation of extra property definition files failed. rc=" + rc); } } catch (IOException | InterruptedException e) { throw new Fault("Compilation of extra property definition files failed.", e); } } return classNames; } /** * Expand a file or directory into a list of java source files. * Non-java source files are only permitted (and ignored) within directories. * @param file the file or directory * @param allowDirs whether directories are permitted or not * @return a list of java source files * @throws Fault if a bad file is found */ private List expandJavaFiles(Path file, boolean allowDirs) throws Fault { List results = new ArrayList<>(); expandJavaFiles(file, allowDirs, true, results); return results; } /** * Expand a file or directory into a list of java source files. * Non-java source files are only permitted (and ignored) within directories. * @param file the file or directory * @param allowDirs whether directories are permitted or not * @param rejectBadFiles whether to throw an exception if a bad file is found * @param results a list of java source files * @throws Fault if a bad file is found */ private void expandJavaFiles(Path file, boolean allowDirs, boolean rejectBadFiles, List results) throws Fault { if (Files.isRegularFile(file)) { if (file.getFileName().toString().endsWith(".java")) { results.add(file); } else { if (rejectBadFiles) { throw new Fault("unexpected file found in extra property definition files: " + file); } } } else if (Files.isDirectory(file)) { if (allowDirs) { for (Path child : FileUtils.listFiles(file)) { expandJavaFiles(child, true, false, results); } } else { if (rejectBadFiles) { throw new Fault("unexpected directory found in extra property definition files" + file); } } } } private String getClassNameFromFile(Path file) throws Fault { try { return getClassNameFromSource(Files.readString(file)); } catch (IOException e) { throw new Fault("Problem reading " + file, e); } } private static final Pattern commentPattern = Pattern.compile("(?s)(\\s+//.*?\n|/\\*.*?\\*/)"); private static final Pattern packagePattern = Pattern.compile("package\\s+(((?:\\w+\\.)*)\\w+)\\s*;"); private static final Pattern classPattern = Pattern.compile("(?:public\\s+)?(?:class|enum|interface|record)\\s+(\\w+)"); private String getClassNameFromSource(String source) throws Fault { // strip comments StringBuilder sb = new StringBuilder(); Matcher matcher = commentPattern.matcher(source); int start = 0; while (matcher.find()) { sb.append(source, start, matcher.start()); start = matcher.end(); } sb.append(source.substring(start)); source = sb.toString(); String packageName = null; matcher = packagePattern.matcher(source); if (matcher.find()) packageName = matcher.group(1); matcher = classPattern.matcher(source); if (matcher.find()) { String className = matcher.group(1); return (packageName == null) ? className : packageName + "." + className; } else { throw new Fault("Could not extract the java class " + "name from the provided source"); } } private List asList(String s) { return (s == null) ? Collections.emptyList() : List.of(s.split("\\s+")); } } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/config/GroupManager.java000066400000000000000000000313301461415321300306540ustar00rootroot00000000000000/* * Copyright (c) 2013, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.config; import java.io.BufferedReader; import java.io.IOException; import java.io.PrintWriter; import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.stream.Collectors; import com.sun.javatest.regtest.util.FileUtils; import com.sun.javatest.regtest.util.GraphUtils; import com.sun.javatest.regtest.util.GraphUtils.Node; import com.sun.javatest.regtest.util.GraphUtils.TarjanNode; import com.sun.javatest.util.I18NResourceBundle; /** * Manage test groups, for use on the jtreg command line. */ public class GroupManager { public static void main(String... args) throws Exception { Path root = Path.of(args[0]); List files = new ArrayList<>(); files.addAll(List.of(args).subList(1, args.length)); PrintWriter out = new PrintWriter(System.err); try { GroupManager gm = new GroupManager(out, root, files); gm.setAllowedExtensions(List.of(".java", ".sh", ".html")); for (Group g: gm.groups.values()) System.err.println(g.name + ": " + g.getFiles()); } finally { out.flush(); } } public static final String GROUP_PREFIX = ":"; public static final String EXCLUDE_PREFIX = "-"; final PrintWriter out; final Path root; final Map groups = new HashMap<>(); private Collection ignoreDirs = Collections.emptySet(); private Collection allowExtns = Collections.emptySet(); public static class InvalidGroup extends Exception { private static final long serialVersionUID = 1L; } GroupManager(PrintWriter out, Path root, List files) throws IOException { this.out = out; this.root = root; for (String f: files) { boolean optional; if (f.startsWith("[") && f.endsWith("]")) { f = f.substring(1, f.length() - 1); optional = true; } else optional = false; Path file = root.resolve(f); if (optional && !Files.exists(file)) { continue; } try (BufferedReader in = Files.newBufferedReader(file)){ Properties p = new Properties(); p.load(in); for (Map.Entry e: p.entrySet()) { String groupName = (String) e.getKey(); String entryDef = (String) e.getValue(); Group g = getGroup(groupName); g.addEntry(new Entry(file, root, entryDef)); } } } validate(); } void setAllowedExtensions(Collection extns) { allowExtns = new HashSet<>(extns); } void setIgnoredDirectories(Collection names) { ignoreDirs = new HashSet<>(names); } public Set getFiles(String group) throws InvalidGroup { Group g = getGroup(group); if (g.invalid) throw new InvalidGroup(); return g.getFiles(); } private Group getGroup(String name) { Group g = groups.get(name); if (g == null) groups.put(name, g = new Group(name)); return g; } public Set getGroups() { return groups.keySet(); } public boolean invalid() { return groups.values().stream().anyMatch(g -> g.invalid); } private void validate() { for (Group g: groups.values()) { if (!g.name.matches("(?i)[a-z][a-z0-9_]*")) { error(g, i18n.getString("gm.invalid.name.for.group")); } for (Entry e: g.entries) { List> allFiles = List.of(e.includeFiles, e.excludeFiles); for (Set files: allFiles) { for (Path f: files) { if (!Files.exists(f)) { URI u = root.toUri().relativize(f.toUri()); error(e.origin, g, i18n.getString("gm.file.not.found", u.getPath())); } } } for (Group eg: e.includeGroups) { if (eg.isEmpty()) error(e.origin, g, i18n.getString("gm.group.not.found", eg.name)); if (eg == g) error(e.origin, g, i18n.getString("gm.group.includes.itself")); } } } final Map> nodes = new HashMap<>(); for (Group g: groups.values()) { nodes.put(g, new TarjanNode<>(g) { @Override public Iterable> getDependencies() { List> deps = new ArrayList<>(); for (Entry e : data.entries) { for (Group g : e.includeGroups) { deps.add(nodes.get(g)); } } return deps; } @Override public String printDependency(Node to) { return to.data.name; } }); } Set>> cycles = GraphUtils.tarjan(nodes.values()); for (Set> cycle : cycles) { if (cycle.size() > 1) { String s = cycle.stream() .map(tn -> tn.data.name) .collect(Collectors.joining(", ")); cycle.stream() .map(tn -> tn.data) .forEach(g -> error(g, i18n.getString("gm.cycle.detected", s))); } } } private void error(Group g, String message) { if (g.entries.isEmpty()) { out.println(i18n.getString("gm.group.prefix", g.name, message)); g.invalid = true; } else { error(g.entries.get(0).origin, g, message); } } private void error(Path f, Group g, String message) { out.println(i18n.getString("gm.file.group.prefix", f, g.name, message)); g.invalid = true; } private class Group { final String name; final List entries; private Set files; boolean invalid; Group(String name) { this.name = name; entries = new ArrayList<>(); } boolean isEmpty() { return entries.isEmpty(); } void addEntry(Entry e) { entries.add(e); } Set getFiles() { if (files == null) { files = new LinkedHashSet<>(); Set inclFiles = new HashSet<>(); Set exclFiles = new HashSet<>(); for (Entry e: entries) { inclFiles.addAll(e.includeFiles); for (Group g: e.includeGroups) inclFiles.addAll(g.getFiles()); exclFiles.addAll(e.excludeFiles); for (Group g: e.excludeGroups) exclFiles.addAll(g.getFiles()); } addFiles(files, inclFiles, exclFiles); } return files; } private void addFiles(Collection files, Collection includes, Collection excludes) { for (Path incl: includes) { if (contains(files, incl) || contains(excludes, incl)) continue; if (Files.isRegularFile(incl)) addFile(files, incl); else if (Files.isDirectory(incl)) { Set excludesForIncl = filter(incl, excludes); if (excludesForIncl.isEmpty()) addFile(files, incl); else addFiles(files, list(incl), excludesForIncl); } } } private void addFile(Collection files, Path file) { files.removeIf(f -> contains(file, f)); files.add(file); } private boolean contains(Collection files, Path file) { for (Path f: files) { if (f.equals(file) || contains(f, file)) { return true; } } return false; } private boolean contains(Path dir, Path file) { return file.startsWith(dir); } private Set filter(Path dir, Collection files) { Set results = null; for (Path f: files) { if (f.startsWith(dir)) { if (results == null) results = new LinkedHashSet<>(); results.add(f); } } return results == null ? Set.of() : results; } private List list(Path file) { List children = new ArrayList<>(); for (Path f: FileUtils.listFiles(file)) { String fn = f.getFileName().toString(); if (Files.isDirectory(f) && !ignoreDirs.contains(fn) || Files.isRegularFile(f) && allowExtns.contains(getExtension(fn))) children.add(f); } return children; } private String getExtension(String name) { int sep = name.lastIndexOf("."); return (sep == -1) ? null : name.substring(sep); } @Override public String toString() { return name; } } class Entry { final Path origin; final Set includeFiles = new LinkedHashSet<>(); final Set excludeFiles = new LinkedHashSet<>(); final Set includeGroups = new LinkedHashSet<>(); final Set excludeGroups = new LinkedHashSet<>(); Entry(Path origin, Path root, String def) { this.origin = origin; def = def.trim(); if (def.length() == 0) return; for (String item: def.split("\\s+")) { boolean exclude = item.startsWith(EXCLUDE_PREFIX); if (exclude) item = item.substring(1); if (item.startsWith(GROUP_PREFIX)) { String name = item.substring(1); (exclude ? excludeGroups : includeGroups).add(getGroup(name)); } else { String name = item; if (name.startsWith("/")) name = name.substring(1); if (name.endsWith("/")) name = name.substring(0, name.length() - 1); Path f = name.equals("") ? root : root.resolve(name); (exclude ? excludeFiles : includeFiles).add(f); } } } @Override public String toString() { return "Entry[origin:" + origin + "inclFiles:" + includeFiles + ",exclFiles:" + excludeFiles + ",inclGroups:" + includeGroups + ",exclGroups:" + excludeGroups + "]"; } } private static final I18NResourceBundle i18n = I18NResourceBundle.getBundleForClass(GroupManager.class); } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/config/IgnoreKind.java000066400000000000000000000027021461415321300303170ustar00rootroot00000000000000/* * Copyright (c) 1997, 2016, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.config; /** * How to handle @ignore tests */ public enum IgnoreKind { QUIET, // quietly ignore @ignore tests ERROR, // give an error if an @ignore test is found RUN // run @ignore tests (ignore the @ignore) } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/config/JDK.java000066400000000000000000000671321461415321300267060ustar00rootroot00000000000000/* * 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 * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.config; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.StringReader; import java.nio.file.Files; import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.TreeSet; import java.util.function.Consumer; import java.util.jar.JarEntry; import java.util.jar.JarFile; import com.sun.javatest.regtest.agent.Flags; import com.sun.javatest.regtest.agent.GetJDKProperties; import com.sun.javatest.regtest.agent.GetSystemProperty; import com.sun.javatest.regtest.agent.JDK_Version; import com.sun.javatest.regtest.agent.SearchPath; import com.sun.javatest.regtest.util.StringUtils; /** * Info about a JDK. * * Some information can be statically determined given its $JAVA_HOME. * Additional information requires code to be executed in a running instance * of the JDK, which may encounter errors that can be reported to * a "logger". The information is typically cached, and so once the information * has been obtained the first time, there will not be errors on subsequent * attempts to access the information. */ public class JDK { /** * Used to report problems that are found. */ public static class Fault extends Exception { private static final long serialVersionUID = 1L; Fault(String msg) { super(msg); } Fault(String msg, Throwable cause) { super(msg, cause); } } /** * Creates a JDK object, given its "$JAVA_HOME" path. * * @param javaHome the "home" directory for the JDK * * @return the JDK object * * @throws InvalidPathException if the path is invalid */ public static JDK of(String javaHome) throws InvalidPathException { return of(Path.of(javaHome)); } /** * Creates a JDK object, given its "$JAVA_HOME" path. * * @param javaHome the "home" directory for the JDK * * @return the JDK object */ public static synchronized JDK of(Path javaHome) { JDK jdk = cache.get(javaHome); if (jdk == null) cache.put(javaHome, jdk = new JDK(javaHome)); return jdk; } private static final Map cache = new HashMap<>(); /** * Creates a JDK object, given its "$JAVA_HOME" path. * * @param jdk the "home" directory for the JDK */ private JDK(Path jdk) { this.jdk = jdk; absJDK = jdk.toAbsolutePath(); } /** * {@inheritDoc} * * Equality is defined in terms of equality of the absolute path for the JDK. */ @Override public boolean equals(Object o) { if (!(o instanceof JDK)) return false; JDK other = (JDK) o; return absJDK.equals(other.absJDK); } @Override public int hashCode() { return absJDK.hashCode(); } @Override public String toString() { return getPath(); } /** * Returns the home directory for the JDK, as specified when the object was created. * * @return the home directory for the JDK * * @see #getHomeDirectory() */ public File getFile() { return jdk.toFile(); } /** * Returns the home directory for the JDK, as specified when the object was created. * * @return the home directory for the JDK */ public Path getHomeDirectory() { return jdk; } /** * Returns the absolute path of the home directory for the JDK. * * @return the absolute path of the home directory for the JDK * * @see #getAbsoluteHomeDirectory() */ public File getAbsoluteFile() { return absJDK.toFile(); } /** * Returns the absolute path of the home directory for the JDK. * * @return the absolute path of the home directory for the JDK */ public Path getAbsoluteHomeDirectory() { return absJDK; } /** * Returns a path for the Java launcher for this JDK. * * @return a path for the Java launcher for this JDK */ public Path getJavaProg() { return getProg("java", false); } /** * Returns a path for the Java compiler for this JDK. * * @return a path for the Java compiler for this JDK */ public Path getJavacProg() { return getProg("javac", false); } /** * Returns a path for a command in the bin directory of this JDK, * optionally including an explicit ".exe" extension, if appropriate. * * @param command the name of the command * @param checkExe whether to include the name of the extension * * @return the path */ public Path getProg(String command, boolean checkExe) { Path bin = absJDK.resolve("bin"); Path prog = bin.resolve(command); if (!Files.exists(prog) && checkExe) { Path prog_exe = bin.resolve(command + ".exe"); if (Files.exists(prog_exe)) { return prog_exe; } } return prog; } /** * Checks whether or not the home directory for this JDK exists. * * @return whether or not the home directory for this JDK exists */ public boolean exists() { return Files.exists(jdk); } /** * Returns the home directory for the JDK as a string, as specified when the object was created. * * @return the home directory for the JDK * * @see #getHomeDirectory() */ public String getPath() { return jdk.toString(); } /** * Returns the absolute path of the home directory for the JDK, as a string. * * @return the absolute path of the home directory for the JDK * * @see #getAbsoluteHomeDirectory() */ public String getAbsolutePath() { return absJDK.toString(); } /** * Returns a search path to access JDK classes. * {@implNote The result contains tools.jar if it exists, and is empty otherwise.} * * @return a search path used to access JDK classes */ public SearchPath getJDKClassPath() { // will return an empty path if tools.jar does not exist return new SearchPath(absJDK.resolve("lib").resolve("tools.jar")); } /** * Returns the version of this JDK, as determined from the * {@code java.specification.version} found when the JDK is run. * * @param params parameters used to locate the class to determine the value of the * system property * @param logger an object to which to write logging messages * * @return the version of this JDK */ // params just used for javatestClassPath // could use values from getProperties if available public JDK_Version getVersion(RegressionParameters params, Consumer logger) { return getJDKVersion(params.getJavaTestClassPath(), logger); } /** * Returns the version of this JDK, as determined from the * {@code java.specification.version}found when the JDK is run. * * @param classpath used to locate the class to determine the value of the * system property * @param logger an object to which to write logging messages * * @return the version of this JDK */ public synchronized JDK_Version getJDKVersion(SearchPath classpath, Consumer logger) { if (jdkVersion == null) { jdkVersion = JDK_Version.forName(getJavaSpecificationVersion(classpath, logger)); } return jdkVersion; } /** * Returns the value of the {@code java.specification.version} property * found when this JDK is run. * * @implNote The value is cached. * * @param getSysPropClassPath used to locate the class to determine the value of the * system property * @param logger an object to which to write logging messages * * @return the value of the {@code java.specification.version} property */ private synchronized String getJavaSpecificationVersion(SearchPath getSysPropClassPath, Consumer logger) { if (javaSpecificationVersion != null) return javaSpecificationVersion; final String VERSION_PROPERTY = "java.specification.version"; for (Info info : infoMap.values()) { if (info.jdkProperties != null) { javaSpecificationVersion = info.jdkProperties.getProperty(VERSION_PROPERTY); if (javaSpecificationVersion != null) return javaSpecificationVersion; } } javaSpecificationVersion = "unknown"; // default ProcessBuilder pb = new ProcessBuilder(); // since we are trying to determine the Java version, we have to assume // the worst, and use CLASSPATH. pb.environment().put("CLASSPATH", getSysPropClassPath.toString()); pb.command(getJavaProg().toString(), GetSystemProperty.class.getName(), VERSION_PROPERTY); pb.redirectErrorStream(true); try { Process p = pb.start(); List lines = getOutput(p, logger); int rc = p.waitFor(); if (rc == 0) { for (String line : lines) { String[] v = line.trim().split("=", 2); if (v.length == 2 && v[0].equals(VERSION_PROPERTY)) { javaSpecificationVersion = v[1]; break; } } if (javaSpecificationVersion.equals("unknown")) { logger.accept("Error getting " + VERSION_PROPERTY + " for " + jdk + ": property not found in output"); lines.forEach(logger::accept); } } else { logger.accept("Error getting " + VERSION_PROPERTY + " for " + jdk + ": exit code " + rc); lines.forEach(logger::accept); } } catch (InterruptedException | IOException e) { // ignore, leave version as default logger.accept("Error getting " + VERSION_PROPERTY + " for " + jdk + ": " + e); } // java.specification.version is not defined in JDK1.1.* if (javaSpecificationVersion == null || javaSpecificationVersion.length() == 0) javaSpecificationVersion = "1.1"; return javaSpecificationVersion; } /** * Returns the output from running {@code java -version} with a given set of VM options. * * @param vmOpts the VM options to be used when {@code java -version} is run * @param logger an object to which to write logging messages * * @return the output from "{@code java -version}" */ public synchronized String getVersionText(Collection vmOpts, Consumer logger) { if (fullVersions == null) fullVersions = new HashMap<>(); final String VERSION_OPTION = "-version"; Set vmOptsSet = new LinkedHashSet<>(vmOpts); String fullVersion = fullVersions.get(vmOptsSet); if (fullVersion == null) { fullVersion = ""; // default List cmdArgs = new ArrayList<>(); cmdArgs.add(getJavaProg().toString()); cmdArgs.addAll(vmOpts); cmdArgs.add(VERSION_OPTION); try { Process p = new ProcessBuilder(cmdArgs) .redirectErrorStream(true) .start(); List lines = getOutput(p, logger); int rc = p.waitFor(); if (rc == 0) { fullVersion = StringUtils.join(lines, "\n"); } else { logger.accept("Error running 'java " + VERSION_OPTION + "' for " + jdk + ": exit code " + rc); lines.forEach(logger::accept); } } catch (InterruptedException | IOException e) { // ignore, leave version as default logger.accept("Error running 'java " + VERSION_OPTION + "' for " + jdk + ": " + e); } fullVersions.put(vmOptsSet, fullVersion); } return fullVersion; } /** * Get properties of the JDK under test. * The properties include: *

    *
  • any properties set up by any classes declared in the extraPropDefns entry in the * TEST.ROOT file *
  • the system properties *
  • additional properties for internal use, such as jtreg.installed.modules *
* * @param params used to help invoke GetJDKProperties * @param logger an object to which to write logging messages * * @return the properties * @throws Fault if an error occurred while getting the properties */ public synchronized Properties getProperties(RegressionParameters params, Consumer logger) throws Fault { Info info = getInfo(params); if (info.jdkProperties == null) { // get default modules as well info.jdkProperties = execGetProperties(params, Collections.emptyList(), List.of("--system-properties", "--modules=boot-layer"), true, logger); } return info.jdkProperties; } /** * Checks whether or not the JDK has modules. * Any errors will be logged to {@link System#err}. * * @implNote Eventually, this should be a simple property of the version. * * @return whether or not the JDK has modules */ public boolean hasModules() { Consumer logger = System.err::println; // whether or not a JDK has modules is independent of the params used, // so arbitrarily use the first (and typically only) one. for (RegressionParameters p: infoMap.keySet()) { return !getDefaultModules(p, logger).isEmpty(); } // jdk.getProperties should be called early on, to avoid this happening throw new IllegalStateException(); } /** * Get the set of default modules for this JDK, taking into account any VM options * like {@code --add-modules} or {@code --limit-modules}. * This is determined by running {@link GetJDKProperties}, which will include * a property giving the set of installed modules, if any. * * @param params to help run {@code GetJDKProperties} * @param logger an object to which to write logging messages * * @return the set of installed modules */ public synchronized Set getDefaultModules(RegressionParameters params, Consumer logger) { Info info = getInfo(params); if (info.defaultModules == null) { try { Properties props = getProperties(params, logger); String m = props.getProperty(GetJDKProperties.JTREG_MODULES); if (m == null) { info.defaultModules = Collections.emptySet(); } else { info.defaultModules = Collections.unmodifiableSet( new LinkedHashSet<>(List.of(m.split(" +")))); } } catch (Fault f) { throw new IllegalStateException(f); } if (showModules) { System.err.println("default modules: " + new TreeSet<>(info.defaultModules)); } } return info.defaultModules; } /** * Get the set of system modules for this JDK, taking into account any VM options * like {@code --add-modules} or {@code --limit-modules}. * This is determined by running {@link GetJDKProperties}, using {@code --add-modules=ALL-SYSTEM} * which will include a property giving the set of installed modules, if any. * * @param params to help run GetJDKProperties * @param logger an object to which to write logging messages * * @return the set of installed modules */ public synchronized Set getSystemModules(RegressionParameters params, Consumer logger) { Info info = getInfo(params); if (info.systemModules == null) { if (getVersion(params, logger).compareTo(JDK_Version.V9) >= 0) { try { // Despite the name, --add-modules=ALL-SYSTEM does not // resolve all system modules: it excludes those marked // "do not resolve by default". This can cause tests // to be incorrectly filtered out because of an @modules // declaration that might refer to one of those modules. // To work around this, by default we get all system modules // using ModuleFinder.ofSystem() on the target platform, // unless the user has explicitly used any --(add|limit)-modules // options, in which case we get the standard modules that // are resolved in the boot layer. String modulesOpt = "--modules=all-system"; for (String vmOpt : params.getTestVMJavaOptions()) { if (vmOpt.matches("--(add|limit)-modules(=.*)?")) { modulesOpt = "--modules=boot-layer"; break; } } Properties props = execGetProperties(params, Collections.emptyList(), // vm options List.of(modulesOpt), false, logger); // requested info from probe String m = props.getProperty(GetJDKProperties.JTREG_MODULES); if (m == null) { info.systemModules = Collections.emptySet(); } else { info.systemModules = Collections.unmodifiableSet( new LinkedHashSet<>(List.of(m.split(" +")))); } } catch (Fault f) { throw new IllegalStateException(f); } } else { info.systemModules = Collections.emptySet(); } if (showModules) { System.err.println("system modules: " + new TreeSet<>(info.systemModules)); } } return info.systemModules; } /** * Checks whether or not the JDK has an "old-style" ct.sym file, * such that you might need to use {@code -XDignore.symbol.file=true} to * access hidden internal API. * * @return whether or not the JDK has an "old-style" ct.sym file. * @implNote Eventually, this should be a simple property of the version. */ public boolean hasOldSymbolFile() { if (hasOldSymbolFile == null) { if (javaSpecificationVersion != null) { JDK_Version v = JDK_Version.forName(javaSpecificationVersion); if (v.compareTo(JDK_Version.V1_5) <= 0 || v.compareTo(JDK_Version.V10) >= 0) { hasOldSymbolFile = false; return hasOldSymbolFile; } } Path ctSym = absJDK.resolve("lib").resolve("ct.sym"); if (Files.exists(ctSym)) { try (JarFile jar = new JarFile(ctSym.toFile())) { JarEntry e = jar.getJarEntry("META-INF/sym/rt.jar/java/lang/Object.class"); hasOldSymbolFile = (e != null); } catch (IOException e) { hasOldSymbolFile = false; } } else { hasOldSymbolFile = false; } } return hasOldSymbolFile; } /** * Executes the {@link GetJDKProperties} utility class in the target JDK. * * @param params parameters used to determine additional classes to run, * and how to compile them * @param extraVMOpts additional VM options to be specified when the class is run * @param opts options to be passed to the utility class * @param includeExtraPropDefns whether or not to compile and run the "extraPropDefn" * classes specified in the test-suite TEST.ROOT file * @param logger an object to which to write logging messages * * @return the properties returns from the utility class. * @throws Fault if any error occurs while getting the properties. */ private Properties execGetProperties(RegressionParameters params, List extraVMOpts, List opts, boolean includeExtraPropDefns, Consumer logger) throws Fault { ExtraPropDefns epd = includeExtraPropDefns ? params.getTestSuite().getExtraPropDefns() : new ExtraPropDefns(); try { epd.compile(params, params.getCompileJDK(), params.getWorkDirectory().getFile("extraPropDefns")); } catch (ExtraPropDefns.Fault e) { throw new Fault(e.getMessage(), e); } JDKOpts jdkOpts = new JDKOpts(); jdkOpts.add("--class-path"); SearchPath cp = new SearchPath(params.getJavaTestClassPath()); cp.append(epd.getClassDir()); jdkOpts.add(cp.toString()); SearchPath bcp = new SearchPath(epd.getBootClassDir()); if (!bcp.isEmpty()) { jdkOpts.add("-Xbootclasspath/a:" + bcp); } params.getBasicTestProperties() .forEach((name, value) -> jdkOpts.add("-D" + name + "=" + value)); List vmOpts = params.getTestVMJavaOptions(); jdkOpts.addAll(vmOpts); jdkOpts.addAll(extraVMOpts); jdkOpts.addAll(epd.getVMOpts()); List cmdArgs = new ArrayList<>(); cmdArgs.add(getJavaProg().toString()); cmdArgs.addAll(jdkOpts.toList()); cmdArgs.add(GetJDKProperties.class.getName()); cmdArgs.addAll(opts); cmdArgs.addAll(epd.getClasses()); try { File scratchDir = params.getWorkDirectory().getFile("scratch"); // The scratch directory probably already exists, but just in case, // we ensure that it does. scratchDir.mkdirs(); final Process p = new ProcessBuilder(cmdArgs) .directory(scratchDir) .start(); asyncCopy(p.getErrorStream(), logger); List lines = readLines(p.getInputStream()); int rc = p.waitFor(); if (rc != 0) { for (String line : lines) { logger.accept(line); } String msg = String.format("failed to get JDK properties:%ncmd: \"%s\"%ncwd: \"%s\"%nexit code: %d", StringUtils.join(cmdArgs, "\" \""), scratchDir, rc); logger.accept(msg); throw new Fault(msg); } return loadProperties(lines, logger); } catch (InterruptedException | IOException e) { logger.accept("Error accessing extra property definitions: " + e); throw new Fault("Error accessing extra property definitions: " + e, e); } } private List readLines(InputStream is) throws IOException { List lines = new ArrayList<>(); try (BufferedReader in = new BufferedReader(new InputStreamReader(is))) { String line; while ((line = in.readLine()) != null) { lines.add(line); } } return lines; } private Properties loadProperties(List lines, Consumer logger) throws Fault { Properties props = new Properties(); try { props.load(new StringReader(String.join("\n", lines))); } catch (IOException e) { logger.accept("Error loading extra property definitions: " + e); lines.forEach(logger::accept); throw new Fault("Error loading extra property definitions: " + e); } return props; } private void asyncCopy(final InputStream in, final Consumer logger) { new Thread(() -> { try { BufferedReader err = new BufferedReader(new InputStreamReader(in)); String line; while ((line = err.readLine()) != null) { logger.accept(line); } } catch (IOException e) { logger.accept("Error reading stderr while accessing properties: " + e); } }).start(); } private List getOutput(Process p, Consumer logger) { List lines = new ArrayList<>(); try (BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()))) { String line; while ((line = r.readLine()) != null) { lines.add(line); } return lines; } catch (IOException e) { logger.accept("Error getting output from process: " + e); logger.accept("Output so far:"); lines.forEach(logger::accept); return Collections.singletonList(e.getMessage()); } } private Info getInfo(RegressionParameters params) { Info info = infoMap.get(params); if (info == null) { infoMap.put(params, info = new Info()); } return info; } private final Path jdk; private final Path absJDK; /** Value of java.specification.version for this JDK. Lazily evaluated as needed. */ private String javaSpecificationVersion; /** Interpreted value of javaSpecificationVersion. Lazily evaluated as needed. */ private JDK_Version jdkVersion; /** Value of java VMOPTS -version for this JDK. Lazily evaluated as needed. */ private Map, String> fullVersions; private Boolean hasOldSymbolFile = null; private final Map infoMap = new HashMap<>(); static class Info { Properties jdkProperties; Set defaultModules; Set systemModules; } private static final boolean showModules = Flags.get("showModules"); } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/config/JDKOpts.java000066400000000000000000000343021461415321300275450ustar00rootroot00000000000000/* * Copyright (c) 1997, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.config; import java.io.File; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import com.sun.javatest.regtest.agent.SearchPath; import com.sun.javatest.regtest.util.FileUtils; import com.sun.javatest.regtest.util.StringUtils; /** * A class to manage lists of options for java and javac, merging them as necessary. * The options that can be merged are those that might reasonably be specified by * the user and by jtreg itself, and for which a repeated value is invalid in some way. */ public class JDKOpts { /** * The JDK options supported by this class. * All options in this set take a value. * Repeated use of any of these options will be merged. * Option names will be converted their canonical form. */ public enum Option { ADD_EXPORTS("--add-exports"), ADD_EXPORTS_PRIVATE("--add-exports-private"), ADD_MODULES("--add-modules"), ADD_OPENS("--add-opens"), ADD_READS("--add-reads"), CLASS_PATH("--class-path", "-classpath", "-cp"), LIMIT_MODULES("--limit-modules"), MODULE_PATH("--module-path", "-p"), MODULE_SOURCE_PATH("--module-source-path"), PATCH_MODULE("--patch-module"), SOURCE_PATH("--source-path", "-sourcepath"); Option(String... names) { this.names = names; } final String[] names; } private final MergeHandler mergeHandler; private String pending; private static final char COMMA = ','; private static final char EQUALS = '='; private static final char NUL = '\0'; private static final char PATHSEP = File.pathSeparatorChar; /** * Returns true if an option should be followed by an argument in the following position. * @param opt the option * @return true if a following argument is to be expected */ public static boolean hasFollowingArg(String opt) { for (Option option: Option.values()) { for (String name: option.names) { if (opt.equals(name) && !name.endsWith(":") && !name.endsWith("=")) return true; } } return false; } /** * Creates an object to normalize a series of JDK options. */ public JDKOpts() { mergeHandler = new MergeHandler(); } /** * Returns the series of normalized options as a list. * @return a list */ public List toList() { return Collections.unmodifiableList(mergeHandler.opts); } /** * Adds a series of options. * @param opts the options. */ public void addAll(List opts) { for (String opt: opts) { add(opt); } } /** * Adds a series of options. * @param opts the options. */ public void addAll(String... opts) { for (String opt: opts) { add(opt); } } /** * Adds a single option. * If the option needs an argument, it will be deferred until the following call, * which will be used as the value. * @param opt the option */ public void add(String opt) { if (pending != null) { mergeHandler.handleOption(pending, opt); pending = null; } else if (hasFollowingArg(opt)) { pending = opt; } else { mergeHandler.handleOption(opt); } } /** * Adds a path-valued option. * If opt ends with ":", a single option is added; otherwise opt and path are added * as two distinct items. * @param opt the option * @param path the path value */ public void addPath(String opt, SearchPath path) { if (path != null && !path.isEmpty()) { if (opt.endsWith(":")) { add(opt + path); } else { add(opt); add(path.toString()); } } } /** * Adds a series of {@code --patch-module} options for the directories * found on a search path. * The directories are assumed to be named for the modules they contain. * Note: jar files on the search path are not supported by this method. * @param patchPath the search path on which to look for modules to be patched */ public void addAllPatchModules(SearchPath patchPath) { if (patchPath != null) { for (Path dir : patchPath.asList()) { List subdirs = FileUtils.listFiles(dir); if (subdirs != null) { Collections.sort(subdirs); // for repeatability; good enough for now for (Path subdir: subdirs) { if (Files.isDirectory(subdir)) { String moduleName = subdir.getFileName().toString(); mergeHandler.handleOption(Option.PATCH_MODULE, "--patch-module", moduleName + "=" + subdir); } } } } } } /** * An option handler to merge multiple instances of the same option. */ private static class MergeHandler extends OptionHandler { private final List opts; private final Map index; MergeHandler() { opts = new ArrayList<>(); index = new HashMap<>(); } @Override protected void handleOption(Option option, String opt, String arg) { switch (option) { case ADD_EXPORTS: updateOptWhitespaceArg("--add-exports", arg, EQUALS, COMMA); break; case ADD_EXPORTS_PRIVATE: case ADD_OPENS: updateOptWhitespaceArg("--add-opens", arg, EQUALS, COMMA); break; case ADD_MODULES: updateOptWhitespaceArg("--add-modules", arg, NUL, COMMA); break; case ADD_READS: updateOptWhitespaceArg("--add-reads", arg, EQUALS, COMMA); break; case CLASS_PATH: updateOptWhitespaceArg("-classpath", arg, NUL, PATHSEP); break; case LIMIT_MODULES: updateOptWhitespaceArg("--limit-modules", arg, NUL, COMMA); break; case MODULE_PATH: updateOptWhitespaceArg("--module-path", arg, NUL, PATHSEP); break; case MODULE_SOURCE_PATH: updateOptWhitespaceArg("--module-source-path", arg, NUL, PATHSEP); break; case PATCH_MODULE: updateOptWhitespaceArg("--patch-module", arg, EQUALS, PATHSEP); break; case SOURCE_PATH: updateOptWhitespaceArg("-sourcepath", arg, NUL, PATHSEP); break; } } @Override protected void handleUnknown(String opt) { opts.add(opt); } /** * Update the list of options with a single-word multivalued option. * This is for options of the form * {@code -option:key value value value } * implying we assume that {@code keysep} is the first character * of its kind in {@code opt}. * @param opt the option name and values to add or merge into the list * @param keySep the separator between the key and the values * @param valSep the separator between values */ private void updateOptAdjacentArg(String opt, char keySep, char valSep) { int i = opt.indexOf(keySep); String key = opt.substring(0, i + 1); String optValues = opt.substring(i + 1); Integer pos = index.get(key); if (pos == null) { pos = opts.size(); opts.add(opt); index.put(key, pos); } else { Set allValues = new LinkedHashSet<>(); String[] oldValues = opts.get(pos).substring(i + 1).split(String.valueOf(valSep)); allValues.addAll(List.of(oldValues)); allValues.addAll(List.of(optValues.split(String.valueOf(valSep)))); StringBuilder sb = new StringBuilder(key); // includes keySep for (String v: allValues) { if (sb.length() > key.length()) { sb.append(valSep); } sb.append(v); } opts.set(pos, sb.toString()); } } private void updateOptWhitespaceArg(String opt, String arg, char keySep, char valueSep) { String argKey; List argValues; if (keySep != 0 && arg.indexOf(keySep) != -1) { argKey = StringUtils.beforePart(arg, keySep); argValues = StringUtils.split(StringUtils.afterPart(arg, keySep), valueSep); } else { argKey = null; argValues = StringUtils.split(arg, valueSep); } String indexKey = (argKey == null) ? opt : opt + "=" + argKey; Integer pos = index.get(indexKey); if (pos == null) { pos = opts.size(); opts.add(opt); opts.add(join(argKey, keySep, argValues, valueSep)); index.put(indexKey, pos); } else { Set allValues = new LinkedHashSet<>(); String old = opts.get(pos + 1); List oldValues = StringUtils.split((argKey == null) ? old : StringUtils.afterPart(old, keySep), valueSep); allValues.addAll(oldValues); allValues.addAll(argValues); opts.set(pos + 1, join(argKey, keySep, allValues, valueSep)); } } /** * Returns a string composed of given constituent parts. * The parts may be an optional initial key, and a series of values with a * specified separator. If a key is provided, it will be followed by the * key separator character in the result. * @param key the key, or null if none * @param keySep the separator to follow the key if one is specified * @param values the values * @param valSep the separator to use if more than one key * @return the composite string */ static String join(String key, char keySep, Collection values, char valSep) { StringBuilder sb = new StringBuilder(); if (key != null) { sb.append(key).append(keySep); } boolean needSep = false; for (String v : values) { if (needSep) { sb.append(valSep); } sb.append(v); needSep = true; } return sb.toString(); } } public static abstract class OptionHandler { public void handleOptions(String... opts) { handleOptions(List.of(opts)); } public void handleOptions(List opts) { Iterator iter = opts.iterator(); while (iter.hasNext()) { String opt = iter.next(); handleOption(opt, iter); } } void handleOption(String opt) { handleOption(opt, Collections.emptyIterator()); } void handleOption(String opt, String arg) { handleOption(opt, Collections.singleton(arg).iterator()); } void handleOption(String opt, Iterator rest) { for (Option o: Option.values()) { for (String name: o.names) { if (name.startsWith("--")) { if (opt.equals(name)) { handleOption(o, opt, rest.next()); return; } else if (opt.startsWith(name + "=")) { handleOption(o, opt, opt.substring(name.length() + 1)); return; } } else { if (name.endsWith(":")) { if (opt.startsWith(name)) { handleOption(o, opt, opt.substring(name.length())); return; } } else if (opt.equals(name)) { handleOption(o, opt, rest.next()); return; } } } } handleUnknown(opt); } protected abstract void handleOption(Option option, String opt, String arg); protected abstract void handleUnknown(String opt); } } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/config/Locations.java000066400000000000000000000737011461415321300302300ustar00rootroot00000000000000/* * Copyright (c) 1997, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.config; import java.io.File; import java.io.IOException; import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; import java.util.EnumSet; import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import com.sun.javatest.TestDescription; import com.sun.javatest.regtest.agent.SearchPath; import com.sun.javatest.regtest.tool.Version; import com.sun.javatest.regtest.util.FileUtils; import com.sun.javatest.regtest.util.StringUtils; /** * Utilities to locate source and class files used by a test. */ public final class Locations { /** * Used to report problems that are found. */ public static class Fault extends Exception { private static final long serialVersionUID = 1L; public Fault(String msg) { super(msg); } public Fault(String msg, Throwable cause) { super(msg, cause); } } /** * A library location. * A library location has a name, as given in a test description, * a directory for its source files, a directory for its class files, * and a kind, as determined by looking at its contents. * As a special case, a library location with no name is used to represent * the location of the source and class files of the test itself. */ public static class LibLocn { public enum Kind { PACKAGE, PRECOMPILED_JAR, SYS_MODULE, USER_MODULE } public final String name; public final Path absSrcDir; public final Path absClsDir; public final Kind kind; LibLocn(String name, Path absSrcDir, Path absClsDir, Kind kind) { this.name = name; this.absSrcDir = absSrcDir; this.absClsDir = absClsDir; this.kind = kind; } @Override public boolean equals(Object other) { if (other instanceof LibLocn) { LibLocn l = (LibLocn) other; return (name == null ? l.name == null : name.equals(l.name) && absSrcDir.equals(l.absSrcDir) && absClsDir.equals(l.absClsDir) && kind == l.kind); } else { return false; } } @Override public int hashCode() { return ((name == null ? 0 : name.hashCode()) << 7) + (absSrcDir.hashCode() << 5) + (absClsDir.hashCode() << 3) + kind.hashCode(); } @Override public String toString() { return "LibLocn(" + name + ",src:" + absSrcDir + ",cls:" + absClsDir + "," + kind + ")"; } } /** * A class location. * A class location has a class name, a source file and a class file. * In addition, it exists in the context of a library location, and * depending on the kind of library, in a module within that library. */ public static class ClassLocn { public final LibLocn lib; public final String optModule; public final String className; public final Path absSrcFile; public final Path absClsFile; ClassLocn(LibLocn lib, String optModule, String className, Path absSrcFile, Path absClsFile) { this.lib = lib; this.optModule = optModule; this.className = className; this.absSrcFile = absSrcFile; this.absClsFile = absClsFile; } public boolean isUpToDate() { return Files.exists(absClsFile) && Files.isReadable(absClsFile) && FileUtils.compareLastModifiedTimes(absClsFile, absSrcFile) > 0; } @Override public String toString() { return "ClassLocn(" + lib.name + "," + optModule + "," + className + "," + absSrcFile + "," + absClsFile + ")"; } } private final RegressionTestSuite testSuite; private final Set systemModules; private final SearchPath jtpath; private final JDK testJDK; private final Path absTestFile; private final Path absBaseSrcDir; private final Path absTestSrcDir; private final Path absBaseClsDir; private final Path absTestClsDir; private final Path absTestPatchDir; private final Path absTestModulesDir; private final Path absTestWorkDir; private final Path relLibDir; private final List libList; /** * Creates an object to handle the various locations for a test. * * @param params the parameters for the test run * @param td the test * @param logger an object to which to write logging messages * * @throws Fault if an error occurs */ public Locations(RegressionParameters params, TestDescription td, Consumer logger) throws Fault { testSuite = params.getTestSuite(); systemModules = params.getTestJDK().getSystemModules(params, logger); jtpath = params.getJavaTestClassPath(); testJDK = params.getTestJDK(); Version v = testSuite.getRequiredVersion(); boolean useUniqueClassDir = (v.version != null) && (v.compareTo(new Version("4.2 b08")) >= 0); absTestFile = td.getFile().toPath().toAbsolutePath(); Path relTestFile = td.getRootRelativeFile().toPath(); Path relTestDir = relTestFile.getParent(); if (relTestDir == null) { relTestDir = Path.of("."); // use normalize later to eliminate "." } String testName = relTestFile.getFileName().toString(); String testId = td.getId(); String uniqueTestSubDir = testName.replaceAll("(?i)\\.[a-z]+$", ((testId == null ? "" : "_" + testId) + ".d")); String packageRoot = td.getParameter("packageRoot"); Path relTestSrcDir = relLibDir = (packageRoot != null) ? Path.of(packageRoot) : relTestDir; absBaseSrcDir = params.getTestSuite().getRootDir().toPath(); absTestSrcDir = absBaseSrcDir.resolve(relTestSrcDir).normalize(); Path workDirRoot = params.getWorkDirectory().getRoot().toPath(); Path relTestWorkDir = relTestDir.resolve(uniqueTestSubDir); absTestWorkDir = workDirRoot.resolve(relTestWorkDir); absBaseClsDir = getThreadSafeDir(workDirRoot.resolve("classes"), params.getConcurrency()); Path relTestClsDir = (packageRoot != null) ? Path.of(packageRoot) : useUniqueClassDir ? relTestDir.resolve(uniqueTestSubDir) : relTestDir; absTestClsDir = absBaseClsDir.resolve(relTestClsDir).normalize(); // The following assumes we will never have test code in a package // or subpackage beginning patches or modules when we also have // test patches or test modules. If that becomes not true, then // we should use another subdir (classes?) for the classes on the // classpath, so that classes, modules and patches are sibling // directories. absTestPatchDir = absTestClsDir.resolve("patches"); absTestModulesDir = absTestClsDir.resolve("modules"); libList = new ArrayList<>(); String libs = td.getParameter("library"); for (String lib: StringUtils.splitWS(libs)) { libList.add(getLibLocn(td, lib)); } } public List getLibs() { return libList; } /** * Gets the library location for a library specified in a test description. * @param td the test description * @param lib the name (path) of the library as specified in the test description * @return the resolved library location * @throws Fault if there is an error resolving the library location */ private LibLocn getLibLocn(TestDescription td, String lib) throws Fault { if (lib.startsWith("/")) { String libTail = lib.substring(1); checkLibPath(Path.of(libTail)); if (Files.exists(absBaseSrcDir.resolve(libTail))) { return createLibLocn(lib, absBaseSrcDir, absBaseClsDir); } else { try { for (File extRootFile: testSuite.getExternalLibRoots(td)) { Path extRoot = extRootFile.toPath(); if (Files.exists(extRoot.resolve(libTail))) { // since absBaseSrcDir/lib does not exist, we can safely // use absBaseClsDir/lib for the compiled classes return createLibLocn(lib, extRoot, absBaseClsDir); } } } catch (RegressionTestSuite.Fault e) { throw new Fault(CANT_FIND_LIB + e); } } } else if (lib.startsWith("${") && lib.endsWith(".jar")) { int end = lib.indexOf("}/"); if (end != -1) { String name = lib.substring(2, end); Path dir = null; if (name.equals("java.home")) { dir = testJDK.getAbsoluteHomeDirectory(); } else if (name.equals("jtreg.home")) { dir = jtpath.asList().get(0).getParent().getParent(); } if (dir != null) { String libTail = lib.substring(end + 2); Path absLib = dir.resolve(libTail); if (Files.exists(absLib)) return new LibLocn(lib, null, absLib, LibLocn.Kind.PRECOMPILED_JAR); } } } else { checkLibPath(relLibDir.resolve(lib)); if (Files.exists(absTestSrcDir.resolve(lib))) return createLibLocn(lib, absTestSrcDir, absBaseClsDir.resolve(relLibDir)); } throw new Fault(CANT_FIND_LIB + lib); } private void checkLibPath(Path lib) throws Fault { Path l = lib.normalize(); if (l.startsWith(Path.of(".."))) { throw new Fault("effective library path is outside the test suite: " + l); } } /** * Creates a library location. * The library kind is inferred by looking at its contents. * @param lib the name (path) of the library as specified in the test description * @param absBaseSrcDir the base directory for the library's source files * @param absBaseClsDir the base directory for the library's class files * @return a library location * @throws Fault if there is an error resolving the library location */ private LibLocn createLibLocn(String lib, Path absBaseSrcDir, Path absBaseClsDir) throws Fault { String relLib = (lib.startsWith("/") ? lib.substring(1) : lib); Path absLib = absBaseSrcDir.resolve(relLib).normalize(); if (Files.isRegularFile(absLib) && absLib.getFileName().toString().endsWith(".jar")) { return new LibLocn(lib, null, absLib, LibLocn.Kind.PRECOMPILED_JAR); } else { if (!Files.isDirectory(absLib)) throw new Fault(BAD_LIB + lib); Path absLibSrcDir = absLib; Path absLibClsDir = absBaseClsDir.resolve(relLib).normalize(); LibLocn.Kind kind = getDirKind(absLibSrcDir); return new LibLocn(lib, absLibSrcDir, absLibClsDir, kind); } } /** * Gets the set of kinds of contents of a source directory. * The set will include: *
    *
  • USER_MODULE, if the source directory contains one or more directories * which in turn contain module-info.java *
  • SYS_MODULE, if the source directory contains one or more directories * directory whose names match that of a system module *
  • PACKAGE, if the source directory contains a directory which is neither * of the above *
* @param absSrcDir the source directory to examine * @return the kinds of libraries found in the given source directory */ public Set getDirKinds(Path absSrcDir) { Set kinds = EnumSet.noneOf(LibLocn.Kind.class); for (Path f : FileUtils.listFiles(absSrcDir)) { if (Files.isDirectory(f)) { if (isSystemModule(f.getFileName().toString())) { kinds.add(LibLocn.Kind.SYS_MODULE); } else if (Files.exists((f.resolve("module-info.java")))) { kinds.add(LibLocn.Kind.USER_MODULE); } else { kinds.add(LibLocn.Kind.PACKAGE); } } else { // ignore for now; could categorize as UNNAMED_PACKAGE? } } return kinds; } /** * Gets the kind of a source directory. * The kind is one of: *
    *
  • USER_MODULE, if the source directory contains directories which in turn contain * module-info.java *
  • SYS_MODULE, if the source directory contains directories whose name matches that * of a system module *
  • PACKAGE, if none of the above *
* It is an error if the source directory contains both user modules and system modules. * @param absSrcDir the source directory * @return the kind of the source directory * @throws Locations.Fault if the directory contains more than one kind of content */ public LibLocn.Kind getDirKind(Path absSrcDir) throws Fault { Set kinds = getDirKinds(absSrcDir); switch (kinds.size()) { case 0: return LibLocn.Kind.PACKAGE; case 1: return kinds.iterator().next(); default: throw new Fault(MIXED_LIB + absSrcDir); } } boolean isSystemModule(String name) { return (systemModules != null) && systemModules.contains(name); } /** * Gets the path of the test defining file. * @return the path */ public Path absTestFile() { return absTestFile; } /** * Gets the path of the test source directory. * @return the path */ public Path absTestSrcDir() { return absTestSrcDir; } /** * Gets the path of the test source directory, or to a module within it. * @param optModule the name of the module, or null for "no module" * @return the path */ public Path absTestSrcDir(String optModule) { return getFile(absTestSrcDir, optModule); } /** * Gets the path of a source file in the test source directory or a module within it. * @param optModule the name of the module, or null for "no module" * @param srcFile the file * @return the path * @throws IllegalArgumentException if the path is not a relative path */ public Path absTestSrcFile(String optModule, File srcFile) { if (srcFile.isAbsolute()) throw new IllegalArgumentException(); return getFile(absTestSrcDir, optModule, srcFile.getPath()); } /** * Gets a search path for the source of a test, consisting of the test source directory, * and the source directories of all libraries of PACKAGE kind. * @return the search path */ // (just) used to set test.src.path or TESTSRCPATH public List absTestSrcPath() { List list = new ArrayList<>(); list.add(absTestSrcDir); for (LibLocn l: libList) { if (l.kind == LibLocn.Kind.PACKAGE) { list.add(l.absSrcDir); } } return list; } /** * Gets a list of the source directories of all libraries of a given kind. * @param kind the kind * @return the directories of the specified kind */ public List absLibSrcList(LibLocn.Kind kind) { List list = new ArrayList<>(); for (LibLocn l: libList) { if (l.kind == kind) { list.add(l.absSrcDir); } } return list; } /** * Gets a list of all jar-file libraries for the test in the test suite. * @return the list of jar-file libraries */ public List absLibSrcJarList() { List list = new ArrayList<>(); for (LibLocn l: libList) { if (l.kind == LibLocn.Kind.PRECOMPILED_JAR) { Path f = l.absClsDir; if (Files.isRegularFile(f) && f.getFileName().toString().endsWith(".jar") && Files.exists(f)) list.add(f); } } return list; } /** * Gets the base directory for all compiled classes. * This is different from the directory for the classes for any specific library * or test. It is used when setting up permissions for tests that use the security * manager, to ensure that a test can read all necessary compiled classes. * @return the base directory */ public Path absBaseClsDir() { return absBaseClsDir; } /** * Gets the directory for the compiled classes of a test in the unnamed module. * @return the directory */ public Path absTestClsDir() { return absTestClsDir; } /** * Gets the directory for the compiled classes in either the unnamed module or * a named module. * @param optModule the name of the module, or null for the unnamed module * @return the directory */ public Path absTestClsDir(String optModule) { if (optModule == null) { return absTestClsDir; } else if (isSystemModule(optModule)) { return absTestPatchDir().resolve(optModule); } else { return absTestModulesDir().resolve(optModule); } } /** * Gets the search path for the classes for a test, consisting of the test class directory, * and the class directories of all libraries of PACKAGE kind. * @return the search path */ // (just) used to set test.class.path or TESTCLASSPATH public List absTestClsPath() { List list = new ArrayList<>(); list.add(absTestClsDir); for (LibLocn l: libList) { switch (l.kind) { case PACKAGE: case PRECOMPILED_JAR: list.add(l.absClsDir); } } return list; } /** * Gets a list of the class directories of all libraries of a given kind. * @param kind the kind * @return the list */ public List absLibClsList(LibLocn.Kind kind) { List list = new ArrayList<>(); for (LibLocn l: libList) { if (l.kind == kind) { list.add(l.absClsDir); } } return list; } /** * Gets a file within the test-specific subdirectory of the work directory. * @param name the name of the subdirectory * @return the file */ public Path absTestWorkFile(String name) { return absTestWorkDir.resolve(name); } /** * Gets the directory in which to store the compiled classes of any user-defined * modules for a test. * @return the directory */ public Path absTestModulesDir() { return absTestModulesDir; } /** * Gets the directory in which to store the compiled classes to patch system * modules for a test. * @return the patch directory */ public Path absTestPatchDir() { return absTestPatchDir; } /** * Locates a set of classes. * The name is as defined for the @build tag. * The following forms are allowed: *
    *
  • C -- class C in the unnamed package in the unnamed module *
  • p.C -- class C in package p in the unnamed module *
  • * -- all classes in the unnamed package in the unnamed module *
  • p.* -- all classes in package p in the unnamed module *
* All forms can be prefixed with "m/" to specify module m instead of the * unnamed package. * The test source directory is searched first, followed by any library directories. * * @param name the name of the classes to be built * @return the locations of the classes identified by {@code name} * @throws Locations.Fault if there is a problem locating any of the classes */ public List locateClasses(String name) throws Fault { List searchLocns; String optModule; String className; int sep = name.indexOf("/"); if (sep > 0) { optModule = name.substring(0, sep); className = name.substring(sep + 1); List moduleLocns = getModuleLocn(optModule); if (moduleLocns.isEmpty()) { throw new Fault("can't find module " + optModule + " in test directory or libraries"); } searchLocns = moduleLocns; } else { optModule = null; className = name; searchLocns = new ArrayList<>(); searchLocns.add(new LibLocn(null, absTestSrcDir, absTestClsDir, LibLocn.Kind.PACKAGE)); for (LibLocn l: libList) { if (l.kind == LibLocn.Kind.PACKAGE) { searchLocns.add(l); } } } List results; if (className.equals("*")) { results = locateClassesInPackage(searchLocns, optModule, null); } else if (className.endsWith(".*")) { String packageName = className.substring(0, className.length() - 2); results = locateClassesInPackage(searchLocns, optModule, packageName); } else { results = locateClass(searchLocns, optModule, className); } if (results.isEmpty()) { if (optModule == null) { throw new Fault("can't find " + className + " in test directory or libraries"); } else { throw new Fault("can't find " + className + " in module " + optModule + " in " + searchLocns.get(0).absSrcDir); } } return results; } /** * Locates a module in either the test source directory or in module libraries. */ List getModuleLocn(String moduleName) { if (moduleName == null) { throw new NullPointerException(); } else if (isSystemModule(moduleName)) { List list = new ArrayList<>(); if (Files.exists(getFile(absTestSrcDir, moduleName))) { list.add(new LibLocn(null, absTestSrcDir, absTestPatchDir(), LibLocn.Kind.SYS_MODULE)); } for (LibLocn l : libList) { if (l.kind == LibLocn.Kind.SYS_MODULE && Files.exists(getFile(l.absSrcDir, moduleName))) { list.add(l); } } return list; } else { if (Files.exists(getFile(absTestSrcDir, moduleName))) { return Collections.singletonList( new LibLocn(null, absTestSrcDir, absTestModulesDir(), LibLocn.Kind.USER_MODULE)); } for (LibLocn l : libList) { if (l.kind == LibLocn.Kind.USER_MODULE && Files.exists(getFile(l.absSrcDir, moduleName))) { return Collections.singletonList(l); } } return Collections.emptyList(); } } /** * Locates the first instance of a class in a series of locations. * @return a singleton list if the file is found; or an empty list otherwise. */ private List locateClass(List locns, String optModule, String className) { for (LibLocn l: locns) { ClassLocn cl = locateClass(l, optModule, className); if (cl != null) { return Collections.singletonList(cl); } } return Collections.emptyList(); } /** * Locates an instance of a class in a given location. * @return the instance, or null if not found. */ private ClassLocn locateClass(LibLocn locn, String optModule, String className) { for (String e: extns) { String relSrc = className.replace('.', File.separatorChar) + e; String relCls = className.replace('.', File.separatorChar) + ".class"; Path sf, cf; if (Files.exists(sf = getFile(locn.absSrcDir, optModule, relSrc))) { cf = getFile(locn.absClsDir, optModule, relCls); return new ClassLocn(locn, optModule, className, sf, cf); } // Special case for file to be directly in the test dir if (locn.name == null && optModule == null) { int sep = relSrc.lastIndexOf(File.separatorChar); if (sep >= 0) { String baseName = relSrc.substring(sep + 1); if (Files.exists(sf = absTestSrcDir.resolve(baseName))) { cf = absTestClsDir.resolve(relCls); return new ClassLocn(locn, null, className, sf, cf); } } } } return null; } /** * Locates the classes for a package in a series of locations. */ private List locateClassesInPackage(List locns, String optModule, String optPackage) throws Fault { List results = new ArrayList<>(); boolean recursive = (optModule != null) && (optPackage == null); for (LibLocn l: locns) { locateClassesInPackage(l, optModule, optPackage, recursive, results); } return results; } /** * Locates the classes for a package in a given location. */ private void locateClassesInPackage(LibLocn l, String optModule, String optPackage, boolean recursive, List results) throws Fault { Path pkgSrcDir, pkgClsDir; if (optPackage == null) { pkgSrcDir = getFile(l.absSrcDir, optModule); pkgClsDir = getFile(l.absClsDir, optModule); } else { String p = optPackage.replace('.', File.separatorChar); pkgSrcDir = getFile(l.absSrcDir, optModule, p); pkgClsDir = getFile(l.absClsDir, optModule, p); } if (!Files.isDirectory(pkgSrcDir)) return; try (DirectoryStream ds = Files.newDirectoryStream(pkgSrcDir)) { for (Path sf : ds) { String fn = sf.getFileName().toString(); if (Files.isDirectory(sf)) { if (recursive) { String subpkg = (optPackage == null) ? fn : optPackage + "." + fn; locateClassesInPackage(l, optModule, subpkg, true, results); } } else if (Files.isReadable(sf) && hasExtn(fn, extns)) { String cn = fn.substring(0, fn.lastIndexOf(".")); String className = (optPackage == null) ? cn : optPackage + "." + cn; Path cf = pkgClsDir.resolve(cn + ".class"); results.add(new ClassLocn(l, optModule, className, sf, cf)); } } } catch (IOException e) { throw new Fault("error reading directory " + pkgSrcDir, e); } } private static final String[] extns = { ".java", ".jasm", ".jcod" }; private Path getFile(Path absBaseDir, String optModule) { return (optModule == null) ? absBaseDir : absBaseDir.resolve(optModule); } private Path getFile(Path absBaseDir, String optModule, String relFile) { return getFile(absBaseDir, optModule).resolve(relFile); } private boolean hasExtn(String name, String... extns) { for (String e: extns) { if (name.endsWith(e)) return true; } return false; } //----------thread safety----------------------------------------------- private static final AtomicInteger uniqueId = new AtomicInteger(0); private static final ThreadLocal uniqueNum = new ThreadLocal<>() { @Override protected Integer initialValue() { return uniqueId.getAndIncrement(); } }; private Path getThreadSafeDir(Path file, int concurrency) { return (concurrency == 1) ? file : file.resolve(String.valueOf(getCurrentThreadId())); } private static int getCurrentThreadId() { return uniqueNum.get(); } //----------misc statics--------------------------------------------------- public static final String CANT_FIND_CLASS = "Can't find source for class: ", LIB_LIST = " in directory-list: ", PATH_TESTCLASS = "Unable to locate test class directory!?", CANT_FIND_LIB = "Can't find library: ", BAD_LIB = "Bad file for library: ", BAD_FILE_IN_LIB = "Bad file in library: ", MIXED_LIB = "Can't mix packages, user modules, and patches for system module in library: "; } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/config/Modules.java000066400000000000000000000172071461415321300277040ustar00rootroot00000000000000/* * Copyright (c) 2016, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.config; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import java.util.WeakHashMap; import com.sun.javatest.TestDescription; import com.sun.javatest.regtest.util.StringUtils; /** * Utility class to handle the entries in a {@code @modules} tag. */ public class Modules implements Iterable { /** * Used to report problems that are found. */ public static class Fault extends Exception { private static final long serialVersionUID = 1L; Fault(String message) { super(message); } } public enum Phase { STATIC, DYNAMIC } /** * Simple container for parsed entry in an @modules tag */ public static class Entry { public final String moduleName; public final String packageName; public final boolean addExports; public final boolean addOpens; Entry(String moduleName, String packageName, boolean addExports, boolean addOpens) { this.moduleName = moduleName; this.packageName = packageName; this.addExports = addExports; this.addOpens = addOpens; } /** * Returns true if an export should be added * @return true if an export should be added */ public boolean needAddExports() { return (packageName != null); } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(moduleName); if (packageName != null) { sb.append("/").append(packageName); String sep = ":"; if (addOpens) { if (addExports) { sb.append(sep).append("+open"); } else { sb.append(sep).append("open"); } } } return sb.toString(); } } /** * Parse an entry in an @modules list. * @param s the entry * @return an Entry * @throws Fault if there is an error in the entry */ public static Entry parse(String s) throws Fault { String moduleName; String packageName = null; boolean addExports = false; boolean addOpens = false; int slash = s.indexOf("/"); if (slash == -1) { moduleName = s; } else { moduleName = s.substring(0, slash); int colon = s.indexOf(":", slash + 1); if (colon == -1) { packageName = s.substring(slash + 1); addExports = true; } else { packageName = s.substring(slash + 1, colon); String[] modifiers = s.substring(colon + 1).split(","); for (String m : modifiers) { switch (m) { case "open": case "private": addOpens = true; break; case "+open": addExports = true; addOpens = true; break; default: throw new Fault("bad modifier: " + m); } } } } if (!isDottedName(moduleName)) { throw new Fault("invalid module name: " + moduleName); } if (packageName != null && !isDottedName(packageName)) { throw new Fault("invalid package name: " + packageName); } return new Entry(moduleName, packageName, addExports, addOpens); } private static boolean isDottedName(String qualId) { for (String id : qualId.split("\\.")) { if (!isValidIdentifier(id)) { return false; } } return true; } private static boolean isValidIdentifier(String id) { if (id.length() == 0) { return false; } if (!Character.isJavaIdentifierStart(id.charAt(0))) { return false; } for (int i = 1; i < id.length(); i++) { if (!Character.isJavaIdentifierPart(id.charAt(i))) { return false; } } return true; } /** * Modules object for use when modules are not in effect. */ public static final Modules noModules = new Modules(); private Modules() { entries = Collections.emptySet(); } /** * Creates a collection of Entry objects for the entries in a test description's @modules tag. * If there is no @modules tag, the collection will be empty. * @param params the parameters for this test run * @param td the test description * @throws Fault if there is an error in the @modules tag. */ public Modules(RegressionParameters params, TestDescription td) throws Fault { String tagEntries = td.getParameter("modules"); if (tagEntries == null) { entries = Collections.emptySet(); } else { entries = new LinkedHashSet<>(); for (String s : tagEntries.trim().split("\\s+")) { entries.add(getEntry(params, s)); } } } /** * Returns true if the test description does not have an @modules tag. * @return true if the test description does not have an @modules tag */ public boolean isEmpty() { return entries.isEmpty(); } /** * Returns an iterator for the entries in the @modules tag. * @return an iterator for the entries in the @modules tag */ @Override // defined by java.lang.Iterable public Iterator iterator() { return entries.iterator(); } @Override public String toString() { return StringUtils.join(entries, " "); } private Entry getEntry(RegressionParameters params, String s) throws Fault { Map cache = caches.computeIfAbsent(params, k -> new HashMap<>()); Entry e = cache.get(s); if (e == null) { cache.put(s, e = parse(s)); } return e; } Set entries; /** * A cache of Module.Entry objects, specific to the parameters for the test run. */ private static final WeakHashMap> caches = new WeakHashMap<>(); } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/config/OS.java000066400000000000000000000147301461415321300266130ustar00rootroot00000000000000/* * Copyright (c) 2011, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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,Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.javatest.regtest.config; import java.lang.management.ManagementFactory; import java.util.ArrayList; import java.util.List; import java.util.Properties; import com.sun.management.OperatingSystemMXBean; /** * Utilities for handling OS name, arch and version. */ public class OS { public final String name; public final String arch; public final String version; public final String family; public final String simple_arch; public final String simple_version; public final int processors; public final long maxMemory; public final long maxSwap; private static OS current; public static OS current() { if (current == null) { String name = System.getProperty("os.name"); String arch = System.getProperty("os.arch"); String version = System.getProperty("os.version"); current = new OS(name, arch, version); } return current; } public static OS forProps(Properties sysProps) { String name = sysProps.getProperty("os.name"); String arch = sysProps.getProperty("os.arch"); String version = sysProps.getProperty("os.version"); return new OS( (name == null) ? "unknown" : name, (arch == null) ? "unknown" : arch, (version == null) ? "unknown" : version); } // On JPRT, we see the following various types of values for these properties // os.arch amd64 // os.arch i386 // os.arch sparc // os.arch x86 // os.name Linux // os.name SunOS // os.name Windows 2003 // os.name Windows XP // os.version 2.6.27.21-78.2.41.fc9.i686 // os.version 2.6.27.21-78.2.41.fc9.x86_64 // os.version 5.1 // os.version 5.10 // os.version 5.2 // // On a Mac, we see the following types of values // os.arch x86_64 // os.arch aarch64 // os.arch universal // os.name Darwin // os.name Mac OS X // os.version 10.6.7 // os.version 10.7.4 // // The JPRT source code also lists the following values for os.arch // sparc, sparcv9, ia64, ppc64, ppc, powerpc, // ppcv2, ppcsflt, arm, armsflt, armvfp public OS(String name, String arch, String version) { this.name = name; this.arch = arch; this.version = version; if (name.startsWith("AIX")) family = "aix"; else if (name.startsWith("Linux")) family = "linux"; else if (name.startsWith("Mac") || name.startsWith("Darwin")) family = "mac"; else if (name.startsWith("OS400") || name.startsWith("OS/400") ) family = "os400"; else if (name.startsWith("SunOS") || name.startsWith("Solaris")) family = "solaris"; else if (name.startsWith("Windows")) family = "windows"; else family = name.replaceFirst("^([^ ]+).*", "$1"); // use first word of name if (arch.contains("64") && !arch.equals("ia64") && !arch.equals("ppc64") && !arch.equals("ppc64le") && !arch.equals("zArch_64") && !arch.equals("loongarch64") && !arch.equals("riscv64") && !arch.equals("aarch64")) simple_arch = "x64"; else if (arch.contains("86")) simple_arch = "i586"; else if (arch.equals("ppc") || arch.equals("powerpc")) simple_arch = "ppc"; else if (arch.equals("s390x") || arch.equals("zArch_64")) simple_arch = "s390x"; else if (arch.equals("mips64") || arch.equals("mips64el")) simple_arch = "mips64"; else simple_arch = arch; final String UNKNOWN = "99.99"; int index; for (index = 0; index < version.length(); index++) { char c = version.charAt(index); if (!Character.isDigit(c) && c != '.') break; } List v = new ArrayList<>(); for (String s: version.substring(0, index).split("\\.")) { if (s.length() > 0) v.add(Integer.valueOf(s)); } switch (v.size()) { case 0: simple_version = UNKNOWN; break; case 1: simple_version = v.get(0) + ".0"; break; default: simple_version = v.get(0) + "." + v.get(1); break; } processors = Runtime.getRuntime().availableProcessors(); OperatingSystemMXBean osMXBean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean(); maxMemory = osMXBean.getTotalPhysicalMemorySize(); maxSwap = osMXBean.getTotalSwapSpaceSize(); } public String toString() { return "[name:" + name + ",arch:" + arch + ",version:" + version + ",family:" + family + ",simple_arch:" + simple_arch + ",simple_version:" + simple_version + ",processors:" + processors + ",maxMemory:" + maxMemory + ",maxSwap:" + maxSwap + "]"; } } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/config/ObservableTestFilter.java000066400000000000000000000055561461415321300323720ustar00rootroot00000000000000/* * Copyright (c) 2011, 2018, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.config; import com.sun.javatest.TestDescription; import com.sun.javatest.TestFilter; import com.sun.javatest.util.DynamicArray; /** * A test filter that supports observers. */ public class ObservableTestFilter extends TestFilter { private TestFilter delegate; private Observer[] observers = new Observer[0]; ObservableTestFilter(TestFilter delegate) { if (delegate == null) throw new NullPointerException(); this.delegate = delegate; } @SuppressWarnings("cast") // temporary; to cover transition of generifying DynamicArray void addObserver(Observer o) { if (o == null) throw new NullPointerException(); observers = (Observer[]) DynamicArray.append(observers, o); } @SuppressWarnings("cast") // temporary; to cover transition of generifying DynamicArray void removeObserver(Observer o) { observers = (Observer[]) DynamicArray.remove(observers, o); } @Override public String getName() { return delegate.getName(); } @Override public String getDescription() { return delegate.getDescription(); } @Override public String getReason() { return delegate.getReason(); } @Override public boolean accepts(TestDescription td) throws Fault { if (delegate.accepts(td)) { return true; } else { // protect against removing observers during notification Observer[] stableObservers = observers; for (int i = stableObservers.length - 1; i >= 0; i--) stableObservers[i].rejected(td, this); return false; } } } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/config/ParseException.java000066400000000000000000000040141461415321300312150ustar00rootroot00000000000000/* * Copyright (c) 1999, 2016, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.config; import com.sun.javatest.regtest.exec.TestRunException; /** * This class defines any error in parsing the provided test description. A * parsing error may occur either during initial examination of the tags in * the finder or during more extensive verification of the run action. */ public final class ParseException extends TestRunException { static final long serialVersionUID = 5598548899306920122L; public ParseException(String msg) { super(PARSE_EXCEPTION + msg); } // ParseException() public ParseException(Throwable t) { super(PARSE_EXCEPTION + t.getMessage()); initCause(t); } //----------misc statics---------------------------------------------------- private static final String PARSE_EXCEPTION = "Parse Exception: "; } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/config/RegressionContext.java000066400000000000000000000175761461415321300317720ustar00rootroot00000000000000/* * Copyright (c) 2014, 2018, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.config; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.function.Consumer; import com.sun.javatest.regtest.agent.JDK_Version; /** * The set of named values used for evaluating expressions in test descriptions. */ public class RegressionContext implements Expr.Context { /** * Returns a default context. * Any errors detected will be reported to {@link System#err}. * * @return a default context */ static RegressionContext getDefault() { try { return new RegressionContext(null, System.err::println); } catch (JDK.Fault f) { throw new IllegalStateException(f); } } /** * Creates a context for used with the specified parameters. * * @param params the parameters * @param logger an object to which to write logging messages * * @throws JDK.Fault if an error occurs while accessing info for this object */ RegressionContext(RegressionParameters params, Consumer logger) throws JDK.Fault { this.params = params; validPropNames = null; values = new HashMap<>(); values.put("null", "null"); JDK_Version jdkVersion; OS os; if (params == null) { jdkVersion = null; os = OS.current(); } else { JDK jdk = params.getTestJDK(); Properties jdkProps = jdk.getProperties(params, logger); for (Map.Entry e: jdkProps.entrySet()) { values.put((String) e.getKey(), (String) e.getValue()); } jdkVersion = JDK_Version.forName(jdkProps.getProperty("java.specification.version")); os = OS.forProps(jdkProps); } values.put("jdk.version", jdkVersion != null ? jdkVersion.name() : "unknown"); values.put("jdk.version.major", jdkVersion != null ? String.valueOf(jdkVersion.major) : "0"); // profile... (JDK 8) // modules... (JDK 9) values.put("os.name", os.name ); values.put("os.arch", os.arch ); values.put("os.simpleArch", os.simple_arch); values.put("os.version", os.version); values.put("os.simpleVersion", os.simple_version); values.put("os.family", os.family); values.put("os.processors", String.valueOf(os.processors)); values.put("os.maxMemory", String.valueOf(os.maxMemory)); values.put("os.maxSwap", String.valueOf(os.maxSwap)); processVMOptions((params == null) ? Collections.emptyList() : params.getTestVMJavaOptions()); } RegressionContext(RegressionContext base, Set validPropNames) { params = base.params; values = base.values; this.validPropNames = validPropNames; } public boolean isValidName(String name) { // Names are validated on the first pass, when the set of valid // test-specific property names is available. On the second pass, // we assume invalid names were detected on the first pass, and so // now all names can be assumed to be valid if (validPropNames == null) return true; if (values.containsKey(name)) return true; if (name.startsWith("vm.opt.")) return true; return validPropNames.contains(name); } public String get(String name) throws Expr.Fault { String v = values.get(name); if (v == null) { return "null"; } else if (v.startsWith("__ERROR__")) { String reason = v.substring("__ERROR__".length()).trim(); if (reason.isEmpty()) { reason = "error determining value"; } throw new Expr.Fault(name + ": " + reason); } else { return v; } } @Override public String toString() { return values.toString(); } private void processVMOptions(List vmOptions) { String gc = null; String compMode = null; Map vmBools = new HashMap<>(); Map vmProps = new HashMap<>(); for (String opt: vmOptions) { if (opt.equals("-" + MODE_MIXED)) { compMode = MODE_MIXED; } else if (opt.equals("-" + MODE_INT)) { compMode = MODE_INT; } else if (opt.equals("-" + MODE_COMP)) { compMode = MODE_COMP; } else if (opt.startsWith(GC_PREFIX) && opt.endsWith(GC_SUFFIX)) { gc = opt.substring(GC_PREFIX.length(), opt.length() - GC_SUFFIX.length()); vmBools.put(opt.substring(ON_PREFIX.length()), true); } else if (opt.startsWith(ON_PREFIX)) { vmBools.put(opt.substring(ON_PREFIX.length()), true); } else if (opt.startsWith(OFF_PREFIX)) { vmBools.put(opt.substring(OFF_PREFIX.length()), false); } else if (opt.startsWith(VM_PREFIX)) { int eq = opt.indexOf('='); if (eq > 0) { String vmPropName = opt.substring(VM_PREFIX.length(), eq); String vmPropValue = opt.substring(eq+1); vmProps.put(vmPropName, vmPropValue); } } } String NULL = "null"; putIfAbsent(values, "vm.flavor", NULL); putIfAbsent(values, "vm.bits", NULL); putIfAbsent(values, "vm.gc", (gc != null) ? gc : NULL); putIfAbsent(values, "vm.compMode", (compMode != null) ? compMode : NULL); for (Map.Entry e: vmBools.entrySet()) { putIfAbsent(values, "vm.opt." + e.getKey(), String.valueOf(e.getValue())); } for (Map.Entry e: vmProps.entrySet()) { putIfAbsent(values, "vm.opt." + e.getKey(), String.valueOf(e.getValue())); } } // replace with Map.putIfAbsent when jtreg uses JDK 1.8 private void putIfAbsent(Map map, String key, String value) { if (!map.containsKey(key)) map.put(key, value); } private static final String VM_PREFIX = "-XX:"; private static final String ON_PREFIX = VM_PREFIX + "+"; private static final String OFF_PREFIX = VM_PREFIX + "-"; private static final String GC_PREFIX = ON_PREFIX + "Use"; private static final String GC_SUFFIX = "GC"; private static final String MODE_MIXED = "Xmixed"; private static final String MODE_INT = "Xint"; private static final String MODE_COMP = "Xcomp"; private final RegressionParameters params; private final Map values; private final Set validPropNames; } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/config/RegressionEnvironment.java000066400000000000000000000034611461415321300326360ustar00rootroot00000000000000/* * 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 * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.config; import java.util.ArrayList; import com.sun.javatest.TestEnvironment; public class RegressionEnvironment extends TestEnvironment { RegressionEnvironment(RegressionParameters params) throws Fault { super("regtest", new ArrayList<>(), new String[] { }); this.params = params; } private RegressionEnvironment(RegressionEnvironment other) { super(other); this.params = other.params; } @Override public TestEnvironment copy() { return new RegressionEnvironment(this); } public final RegressionParameters params; } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/config/RegressionKeywords.java000066400000000000000000000041651461415321300321430ustar00rootroot00000000000000/* * Copyright (c) 2015, 2016, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.config; /** * Utilities for handling keyword expressions. */ public class RegressionKeywords { static class Fault extends Exception { private static final long serialVersionUID = 1L; Fault(String msg) { super(msg); } } static void validateKey(String key) throws Fault { if (key.length() == 0) throw new Fault("empty"); char c = key.charAt(0); if (!(Character.isUnicodeIdentifierStart(c) || (allowNumericKeywords && Character.isDigit(c)))) { throw new Fault("invalid character: " + c); } for (int i = 1; i < key.length(); i++) { c = key.charAt(i); if (!(Character.isUnicodeIdentifierPart(c) || c == '-')) { throw new Fault("invalid character: " + c); } } } public static final boolean allowNumericKeywords = true; } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/config/RegressionParameters.java000066400000000000000000001460511461415321300324400ustar00rootroot00000000000000/* * Copyright (c) 2001, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.config; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.nio.file.Files; import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.function.Consumer; import java.util.function.Function; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; import java.util.stream.Collectors; import java.util.stream.Stream; import com.sun.interview.Interview; import com.sun.interview.Question; import com.sun.javatest.CompositeFilter; import com.sun.javatest.ExcludeList; import com.sun.javatest.InterviewParameters; import com.sun.javatest.Parameters; import com.sun.javatest.ProductInfo; import com.sun.javatest.Status; import com.sun.javatest.TestDescription; import com.sun.javatest.TestEnvironment; import com.sun.javatest.TestFilter; import com.sun.javatest.interview.BasicInterviewParameters; import com.sun.javatest.regtest.agent.JDK_Version; import com.sun.javatest.regtest.agent.SearchPath; import com.sun.javatest.regtest.exec.TimeoutHandlerProvider; import com.sun.javatest.regtest.util.FileUtils; import com.sun.javatest.regtest.util.StringUtils; import com.sun.javatest.util.I18NResourceBundle; import static com.sun.javatest.regtest.util.StringUtils.join; public final class RegressionParameters extends BasicInterviewParameters implements Parameters.EnvParameters { private final Consumer logger; /** * Creates an object to handle the parameters for a test run. * * @param tag a string to identify the set of parameters * @param testSuite the test suite * @param logger an object to which to write logging messages * * @throws InterviewParameters.Fault if a problem occurs while creating this object */ public RegressionParameters(String tag, RegressionTestSuite testSuite, Consumer logger) throws InterviewParameters.Fault { super(tag, testSuite); this.logger = logger; setTitle("jtreg Configuration Editor"); // I18N setEdited(false); } //--------------------------------------------------------------------- @Override public RegressionTestSuite getTestSuite() { return (RegressionTestSuite) super.getTestSuite(); } //--------------------------------------------------------------------- public void setTests(Collection tests) { setTests(tests == null ? null : tests.toArray(new String[0])); } public void setTests(String[] tests) { MutableTestsParameters mtp = (MutableTestsParameters) getTestsParameters(); mtp.setTests(tests); } public void setKeywordsExpr(String expr) { MutableKeywordsParameters mkp = (MutableKeywordsParameters) getKeywordsParameters(); mkp.setKeywords(MutableKeywordsParameters.EXPR, expr); } /** * This method is to workaround an earlier workaround * (in {@link BasicInterviewParameters#getMaxConcurrency()}) * for the max concurrency. * @return the maximum permitted concurrency */ @Override protected int getMaxConcurrency() { return Parameters.ConcurrencyParameters.MAX_CONCURRENCY; } public void setConcurrency(int conc) { MutableConcurrencyParameters mcp = (MutableConcurrencyParameters) getConcurrencyParameters(); mcp.setConcurrency(conc); } public void setTimeoutFactor(float tfac) { MutableTimeoutFactorParameters mtfp = (MutableTimeoutFactorParameters) getTimeoutFactorParameters(); mtfp.setTimeoutFactor(tfac); } public void setExcludeLists(Path[] files) { MutableExcludeListParameters mep = (MutableExcludeListParameters) getExcludeListParameters(); mep.setExcludeFiles(FileUtils.toFiles(files)); } public File[] getExcludeLists() { MutableExcludeListParameters mep = (MutableExcludeListParameters) getExcludeListParameters(); return mep.getExcludeFiles() != null ? mep.getExcludeFiles() : new File[0]; } public void setPriorStatusValues(boolean[] b) { MutablePriorStatusParameters mpsp = (MutablePriorStatusParameters) getPriorStatusParameters(); mpsp.setPriorStatusValues(b); } //--------------------------------------------------------------------- @Override public TestEnvironment getEnv() { try { return new RegressionEnvironment(this); } catch (com.sun.javatest.TestEnvironment.Fault e) { return null; } } @Override public Parameters.EnvParameters getEnvParameters() { return this; } @Override protected Question getEnvFirstQuestion() { return getEnvSuccessorQuestion(); } //--------------------------------------------------------------------- /* Although a filter can throw TestFilter.Fault, currently all such * exceptions are silently ignored! * The following map provides a way of recording whether a problem * was encountered by a filter. */ public Map filterFaults = new HashMap<>(); /* A RegressionContext is used by various filters, but initializing it may throw an * exception. Therefore, it should be initialized explicitly, and the exception * handled, rather than lazily, in circumstances where the exception might be ignored. */ private Expr.Context exprContext; public void initExprContext() throws JDK.Fault { exprContext = new RegressionContext(this, logger); } public Expr.Context getExprContext() { return exprContext; } @Override public TestFilter getRelevantTestFilter() { if (relevantTestFilter == UNSET) { List filters = new ArrayList<>(); TestFilter mf = getModulesFilter(); if (mf != null) filters.add(mf); TestFilter rf = getRequiresFilter(); filters.add(rf); TestFilter tlf = getTimeLimitFilter(); if (tlf != null) filters.add(tlf); TestFilter mlf = getMatchListFilter(); if (mlf != null) filters.add(mlf); final TestFilter f = new CompositeFilter(filters.toArray(new TestFilter[0])); return new CachingTestFilter(f.getName(), f.getDescription(), f.getReason()) { @Override protected String getCacheKey(TestDescription td) { return td.getRootRelativeURL(); } @Override protected boolean getCacheableValue(TestDescription td) throws Fault { return f.accepts(td); } }; } return relevantTestFilter; } TestFilter relevantTestFilter = UNSET; TestFilter getModulesFilter() { JDK jdk = getTestJDK(); if (jdk == null || jdk.getVersion(this, logger).compareTo(JDK_Version.V9) < 0) return null; final Set availModules = jdk.getSystemModules(this, logger); if (availModules.isEmpty()) return null; return new CachingTestFilter( "ModulesFilter", "Select tests for which all required modules are available", "A required module is not available") { private static final String MODULES = "modules"; @Override protected String getCacheKey(TestDescription td) { return td.getParameter(MODULES); } @Override public boolean getCacheableValue(TestDescription td) { String reqdModules = td.getParameter(MODULES); if (reqdModules == null) return true; for (String m: reqdModules.split(" ")) { if (m.length() == 0) continue; int slash = m.indexOf("/"); String name = slash == -1 ? m : m.substring(0, slash); if (!availModules.contains(name)) return false; } return true; } }; } TestFilter getRequiresFilter() { return new CachingTestFilter( "RequiresFilter", "Select tests that satisfy a given set of platform requirements", "The platform does not meet the specified requirements") { private static final String REQUIRES = "requires"; @Override protected String getCacheKey(TestDescription td) { return td.getParameter(REQUIRES); } @Override public boolean getCacheableValue(TestDescription td) { try { String requires = td.getParameter(REQUIRES); if (requires == null) return true; return Expr.parse(requires, exprContext).evalBoolean(exprContext); } catch (Expr.Fault ex) { filterFaults.put(td.getRootRelativeURL(), "Error evaluating expression: " + ex.getMessage()); // While it may seem more obvious to return false in this case, // that would make it easier to overlook the fault since the // test will have been quietly filtered out. // By returning true, we give downstream code the opportunity // to check whether a filter fault occurred, and to report // the error back to the user. return true; } } }; } TestFilter getTimeLimitFilter() { if (timeLimit <= 0) return null; return new CachingTestFilter( "TestLimitFilter", "Select tests that do not exceed a specified timeout value", "Test declares a timeout which exceeds the requested time limit") { final String MAX_TIMEOUT = "maxTimeout"; @Override protected String getCacheKey(TestDescription td) { return td.getParameter(MAX_TIMEOUT); } @Override public boolean getCacheableValue(TestDescription td) { String maxTimeoutValue = td.getParameter(MAX_TIMEOUT); if (maxTimeoutValue != null) { try { int maxTimeout = Integer.parseInt(maxTimeoutValue); if (maxTimeout == 0 || maxTimeout > timeLimit) return false; } catch (NumberFormatException e) { // ignore } } return true; } }; } private static class TestListWithPlatforms { private static Set getPlatforms(OS os) { // On JPRT, we see the following various types of values for these properties // os.arch amd64 // os.arch i386 // os.arch sparc // os.arch x86 // os.name Linux // os.name SunOS // os.name Windows 2003 // os.name Windows XP // os.version 2.6.27.21-78.2.41.fc9.i686 // os.version 2.6.27.21-78.2.41.fc9.x86_64 // os.version 5.1 // os.version 5.10 // os.version 5.2 // On a Mac, we see the following types of values // os.arch x86_64 // os.arch universal // os.name Darwin // os.name Mac OS X // os.version 10.6.7 // os.version 10.7.4 // ProblemList.txt uses the following encoding // generic-all Problems on all platforms // generic-ARCH Where ARCH is one of: sparc, sparcv9, x64, i586, etc. // OSNAME-all Where OSNAME is one of: solaris, linux, windows // OSNAME-ARCH Specific on to one OSNAME and ARCH, e.g. solaris-x64 // OSNAME-REV Specific on to one OSNAME and REV, e.g. solaris-5.8 Set platforms = new HashSet<>(); for (String p: List.of(os.name, os.name.replaceAll("\\s", ""), os.family, "generic")) { for (String q: List.of("", os.arch, os.simple_arch, os.version, os.simple_version, "all")) { String ep = q.isEmpty() ? p : p + "-" + q; platforms.add(ep.toLowerCase()); } } return platforms; } private final ExcludeList el; private final Set osPlatforms; TestListWithPlatforms(ExcludeList el, OS os) { this.el = el; this.osPlatforms = getPlatforms(os); } public boolean match(TestDescription td) { ExcludeList.Entry e = el.getEntry(td.getRootRelativeURL()); if (e == null) { return false; } String[] platforms = e.getPlatforms(); if (platforms.length == 0 || (platforms.length == 1 && platforms[0].length() == 0)) { // allow for old ProblemList.txt format String[] bugIds = e.getBugIdStrings(); if (bugIds.length > 0 && !bugIds[0].matches("0|([1-9][0-9,]*)")) platforms = bugIds; } if (platforms.length == 0 || (platforms.length == 1 && platforms[0].length() == 0)) { return true; } for (String p: platforms) { if (osPlatforms.contains(p.toLowerCase())) { return true; } } return false; } } /** * {@inheritDoc} * * Use a caching filter partly for performance reasons, and partly to make * it easier to calculate the number of rejected tests. Simply counting * the number of true/false results is insufficient because the filter * may be called more than once per test. An alternative approach is to use * an ObservableTestFilter, and count the number of of true/false results in * between Harness.Observer.startingTestRun and Harness.Observer.finishedTestRun. * But that doesn't work correctly since the readAheadTestIterator in Harness * is created before the notification to Harness.Observer.startingTestRun. * * @return a filter based on the current exclude list(s) */ @Override public CachingTestFilter getExcludeListFilter() { if (excludeListFilter == UNSET) { final ExcludeList el = getExcludeList(); if (el == null) { excludeListFilter = null; } else { excludeListFilter = new CachingTestFilter( "jtregExcludeListFilter", "Select tests which are not excluded on any exclude list", "Test has been excluded by an exclude list") { final TestListWithPlatforms list = new TestListWithPlatforms(el, getTestOS()); @Override protected String getCacheKey(TestDescription td) { return td.getRootRelativeURL(); } @Override public boolean getCacheableValue(TestDescription td) { return !list.match(td); } }; } } return excludeListFilter; } private CachingTestFilter excludeListFilter = UNSET; private TestFilter getMatchListFilter() { if (matchListFilter == UNSET) { List matchList = getMatchLists(); if (matchList.isEmpty()) { matchListFilter = null; } else { final ExcludeList el; try { el = new ExcludeList(matchList.stream() .map(Path::toFile) .toArray(File[]::new)); } catch (ExcludeList.Fault | IOException e) { throw new Error(e); } matchListFilter = new CachingTestFilter( "jtregMatchListFilter", "Select tests which are in a match list", "Test has not been matched by a match list") { final TestListWithPlatforms list = new TestListWithPlatforms(el, getTestOS()); @Override protected String getCacheKey(TestDescription td) { return td.getRootRelativeURL(); } @Override public boolean getCacheableValue(TestDescription td) { return list.match(td); } }; } } return matchListFilter; } private TestFilter matchListFilter = UNSET; /** * {@inheritDoc} * * Use a caching filter partly for performance reasons, and partly to make * it easier to analyze the rejected tests. * * @return a filter based on the keywords given on the command line. */ @Override public KeywordsTestFilter getKeywordsFilter() { if (keywordsFilter == UNSET_KEYWORDS_FILTER) { TestFilter f = super.getKeywordsFilter(); keywordsFilter = (f == null) ? null : new KeywordsTestFilter(f); } return keywordsFilter; } private KeywordsTestFilter keywordsFilter = UNSET_KEYWORDS_FILTER; public static class KeywordsTestFilter extends TestFilter { private final TestFilter delegate; public final Set ignored = new HashSet<>(); KeywordsTestFilter(TestFilter delegate) { this.delegate = delegate; } @Override public String getName() { return delegate.getName(); } @Override public String getDescription() { return delegate.getDescription(); } @Override public String getReason() { return delegate.getReason(); } @Override public boolean accepts(TestDescription td) throws Fault { // for standard jtreg tests, there's no point in caching the // evaluation of the keywords, because each test probably has a // unique set of keywords, by virtue of implicit keywords, // such as for @bug. However, we can record the ignored tests. boolean ok = delegate.accepts(td); if (!ok && td.getKeywordTable().contains("ignore")) { ignored.add(td.getRootRelativeURL()); } return ok; } } private static final CachingTestFilter UNSET = new CachingTestFilter("", "", "") { public String getCacheKey(TestDescription td) { throw new IllegalStateException(); } @Override public boolean getCacheableValue(TestDescription td) { throw new IllegalStateException(); } }; private static final KeywordsTestFilter UNSET_KEYWORDS_FILTER = new KeywordsTestFilter(UNSET); @Override public TestFilter getPriorStatusFilter() { if (priorStatusFilter == UNSET) { final TestFilter psf = super.getPriorStatusFilter(); if (psf == null) { priorStatusFilter = null; } else { priorStatusFilter = new CachingTestFilter( "jtregPriorStatusFilter", "Select tests which match a specified status", "Test did not match a specified status") { @Override protected String getCacheKey(TestDescription td) { return td.getRootRelativeURL(); } @Override public boolean getCacheableValue(TestDescription td) throws Fault { return psf.accepts(td); } }; } } return priorStatusFilter; } private CachingTestFilter priorStatusFilter = UNSET; //--------------------------------------------------------------------- // The following (load and save) are an interim consequence of not using proper // interview questions to store configurations values. // The critical values to preserve are any that may be set by direct setXYZ methods // below. // A better solution is to migrate to using interview questions where possible, // and potentially allow the values to be modified via the Config Editor private static final String ENVVARS = ".envVars"; private static final String CHECK = ".check"; private static final String COMPILE_JDK = ".compilejdk"; private static final String TEST_JDK = ".testjdk"; private static final String EXEC_MODE = ".execMode"; private static final String TEST_VM_OPTIONS = ".testVMOpts"; private static final String TEST_COMPILER_OPTIONS = ".testCompilerOpts"; private static final String TEST_JAVA_OPTIONS = ".testJavaOpts"; private static final String IGNORE = ".ignore"; private static final String RETAIN_ARGS = ".retain"; private static final String JUNIT = ".junit"; private static final String TESTNG = ".testng"; private static final String ASMTOOLS = ".asmtools"; private static final String TIMELIMIT = ".timeLimit"; private static final String REPORTDIR = ".reportDir"; private static final String EXCLUSIVE_LOCK = ".exclLock"; private static final String NATIVEDIR = ".nativeDir"; private static final String TIMEOUT_HANDLER = ".timeoutHandler"; private static final String TIMEOUT_HANDLER_PATH = ".timeoutHandlerPath"; private static final String TIMEOUT_HANDLER_TIMEOUT = ".timeoutHandlerTimeout"; private static final String CUSTOM_TEST_THREAD_FACTORY = ".testThreadFactory"; private static final String CUSTOM_TEST_THREAD_FACTORY_PATH = ".testThreadFactoryPath"; private static final String TEST_QUERIES = ".testQueries"; @Override public void load(Map data, boolean checkChecksum) throws Interview.Fault { super.load(data, checkChecksum); String prefix = getTag(); try { String v; v = data.get(prefix + ENVVARS); if (v != null) setEnvVars(deserializeEnv(v, "\n")); v = data.get(prefix + CHECK); if (v != null) setCheck(v.equals("true")); v = data.get(prefix + EXEC_MODE); if (v != null) setExecMode(ExecMode.valueOf(v)); v = data.get(prefix + IGNORE); if (v != null) setIgnoreKind(IgnoreKind.valueOf(v)); v = data.get(prefix + COMPILE_JDK); if (v != null) setCompileJDK(JDK.of(v)); v = data.get(prefix + TEST_JDK); if (v != null) setTestJDK(JDK.of(v)); v = data.get(prefix + TEST_VM_OPTIONS); if (v != null && v.length() > 0) setTestVMOptions(List.of(StringUtils.splitSeparator("\n", v))); v = data.get(prefix + TEST_COMPILER_OPTIONS); if (v != null && v.length() > 0) setTestCompilerOptions(List.of(StringUtils.splitSeparator("\n", v))); v = data.get(prefix + TEST_JAVA_OPTIONS); if (v != null && v.length() > 0) setTestJavaOptions(List.of(StringUtils.splitSeparator("\n", v))); v = data.get(prefix + RETAIN_ARGS); if (v != null && v.length() > 0) setRetainArgs(List.of(StringUtils.splitSeparator("\n", v))); v = data.get(prefix + JUNIT); if (v != null) setJUnitPath(new SearchPath(v)); v = data.get(prefix + TESTNG); if (v != null) setTestNGPath(new SearchPath(v)); v = data.get(prefix + ASMTOOLS); if (v != null) setAsmToolsPath(new SearchPath(v)); v = data.get(prefix + TIMELIMIT); if (v != null) setTimeLimit(Integer.parseInt(v)); v = data.get(prefix + REPORTDIR); if (v != null) setReportDir(Path.of(v)); v = data.get(prefix + EXCLUSIVE_LOCK); if (v != null) setExclusiveLock(Path.of(v)); v = data.get(prefix + NATIVEDIR); if (v != null) setNativeDir(Path.of(v)); v = data.get(prefix + TIMEOUT_HANDLER); if (v != null) setTimeoutHandler(v); v = data.get(prefix + TIMEOUT_HANDLER_PATH); if (v != null) setTimeoutHandlerPath(v); v = data.get(prefix + TIMEOUT_HANDLER_TIMEOUT); if (v != null) setTimeoutHandlerTimeout(v); v = data.get(prefix + CUSTOM_TEST_THREAD_FACTORY); if (v != null) setTestThreadFactory(v); v = data.get(prefix + CUSTOM_TEST_THREAD_FACTORY_PATH); if (v != null) setTestThreadFactoryPath(v); v = data.get(prefix + TEST_QUERIES); if (v != null) { setTestQueries(List.of(StringUtils.splitSeparator("\n", v))); } } catch (InvalidPathException e) { // This is unlikely to happen, but pretty serious if it does. // Since we only put valid paths into the parameters, there should be // no issue retrieving them after the save-load sequence. throw new Interview.Fault(i18n, "rp.badPath", e.getInput(), e.getMessage()); } } public void save(Map data) { super.save(data); String prefix = getTag(); if (envVars != null) data.put(prefix + ENVVARS, serializeEnv(envVars, "\n")); data.put(prefix + CHECK, String.valueOf(check)); data.put(prefix + EXEC_MODE, String.valueOf(execMode)); data.put(prefix + IGNORE, String.valueOf(ignoreKind)); if (testJDK != null) data.put(prefix + TEST_JDK, testJDK.getPath()); if (compileJDK != null) data.put(prefix + COMPILE_JDK, compileJDK.getPath()); if (retainArgs != null && retainArgs.size() > 0) data.put(prefix + RETAIN_ARGS, join(retainArgs, "\n")); if (testVMOpts != null && testVMOpts.size() > 0) data.put(prefix + TEST_VM_OPTIONS, join(testVMOpts, "\n")); if (testCompilerOpts != null && testCompilerOpts.size() > 0) data.put(prefix + TEST_COMPILER_OPTIONS, join(testCompilerOpts, "\n")); if (testJavaOpts != null && testJavaOpts.size() > 0) data.put(prefix + TEST_JAVA_OPTIONS, join(testJavaOpts, "\n")); if (junitPath != null) data.put(prefix + JUNIT, junitPath.toString()); if (testngPath != null) data.put(prefix + TESTNG, testngPath.toString()); if (asmToolsPath != null) data.put(prefix + ASMTOOLS, asmToolsPath.toString()); if (timeLimit > 0) data.put(prefix + TIMELIMIT, String.valueOf(timeLimit)); if (reportDir != null) data.put(prefix + REPORTDIR, reportDir.toString()); if (exclusiveLock != null) data.put(prefix + EXCLUSIVE_LOCK, exclusiveLock.toString()); if (nativeDir != null) data.put(prefix + NATIVEDIR, nativeDir.toString()); if (timeoutHandlerClassName != null) data.put(prefix + TIMEOUT_HANDLER, timeoutHandlerClassName); if (timeoutHandlerPath != null) { StringBuilder sb = new StringBuilder(); String sep = ""; for (Path file: timeoutHandlerPath) { sb.append(sep).append(file); sep = File.pathSeparator; } data.put(prefix + TIMEOUT_HANDLER_PATH, sb.toString()); } if (timeoutHandlerTimeout != -1) { // -1: default; 0: no timeout; >0: timeout in seconds data.put(prefix + TIMEOUT_HANDLER_TIMEOUT, String.valueOf(timeoutHandlerTimeout)); } if (testThreadFactory != null) { data.put(prefix + CUSTOM_TEST_THREAD_FACTORY, testThreadFactory); } if (testThreadFactoryPath != null) { data.put(prefix + CUSTOM_TEST_THREAD_FACTORY_PATH, testThreadFactoryPath); } if (testQueries != null) { data.put(prefix + TEST_QUERIES, join(testQueries, "\n")); } } //--------------------------------------------------------------------- private Map deserializeEnv(String envString, String sep) { Map env; if ((envString != null) && (envString.length() != 0)) { env = new LinkedHashMap<>(); String[] envArr = StringUtils.splitSeparator(sep, envString); for (String e : envArr) { String[] split = StringUtils.splitSeparator("=", e); env.put(split[0], split[1]); } return Collections.unmodifiableMap(env); } else { return Collections.emptyMap(); } } private String serializeEnv(Map env, String sep) { StringBuilder envString = new StringBuilder(); int cnt = env.size(); for(Map.Entry var : env.entrySet()) { envString .append(var.getKey()) .append("=") .append(var.getValue()); cnt--; if (cnt != 0) { envString.append(sep); } } return envString.toString(); } public Map getEnvVars() { if (envVars == null) { String envVarStr = System.getProperty("envVars"); envVars = deserializeEnv(envVarStr, ","); } return envVars; } public void setEnvVars(Map envVars) { if (envVars == null) { this.envVars = Collections.emptyMap(); } else { this.envVars = Collections.unmodifiableMap(new LinkedHashMap<>(envVars)); } } private Map envVars; //--------------------------------------------------------------------- public boolean isCheck() { return check; } public void setCheck(boolean check) { this.check = check; } private boolean check; //--------------------------------------------------------------------- public void setExecMode(ExecMode execMode) { this.execMode = execMode; } public ExecMode getExecMode() { return execMode; } ExecMode execMode; //--------------------------------------------------------------------- public void setIgnoreKind(IgnoreKind ignoreKind) { this.ignoreKind = Objects.requireNonNull(ignoreKind); } public IgnoreKind getIgnoreKind() { return ignoreKind; } IgnoreKind ignoreKind = IgnoreKind.ERROR; // non-null default //--------------------------------------------------------------------- public void setTimeLimit(int timeLimit) { this.timeLimit = timeLimit; } int getTimeLimit() { return timeLimit; } int timeLimit; //--------------------------------------------------------------------- public void setCompileJDK(JDK compileJDK) { this.compileJDK = Objects.requireNonNull(compileJDK); } public JDK getCompileJDK() { return compileJDK; } private JDK compileJDK; //--------------------------------------------------------------------- public void setTestJDK(JDK testJDK) { this.testJDK = Objects.requireNonNull(testJDK); } public JDK getTestJDK() { return testJDK; } private JDK testJDK; //--------------------------------------------------------------------- public void setJUnitPath(SearchPath junitPath) { this.junitPath = Objects.requireNonNull(junitPath); } public SearchPath getJUnitPath() { return junitPath; } private SearchPath junitPath; public boolean isJUnitAvailable() { return (junitPath != null) && !junitPath.isEmpty(); } //--------------------------------------------------------------------- public void setTestNGPath(SearchPath testngPath) { this.testngPath = Objects.requireNonNull(testngPath); } public SearchPath getTestNGPath() { return testngPath; } private SearchPath testngPath; public boolean isTestNGAvailable() { return (testngPath != null) && !testngPath.isEmpty(); } //--------------------------------------------------------------------- public void setAsmToolsPath(SearchPath asmToolsPath) { this.asmToolsPath = Objects.requireNonNull(asmToolsPath); } public SearchPath getAsmToolsPath() { return asmToolsPath; } private SearchPath asmToolsPath; //--------------------------------------------------------------------- public SearchPath getJavaTestClassPath() { if (javaTestClassPath == null) { Path jtClsDir = ProductInfo.getJavaTestClassDir().toPath(); javaTestClassPath = new SearchPath(jtClsDir); if (jtClsDir.getFileName().toString().equals("javatest.jar")) { Path installDir = jtClsDir.getParent(); // append jtreg.jar or exploded directory to the search path Path jtreg = installDir.resolve("jtreg.jar"); if (Files.exists(jtreg)) { javaTestClassPath.append(jtreg); } else try { // use code source location of this class instead URL location = getClass().getProtectionDomain().getCodeSource().getLocation(); javaTestClassPath.append(Path.of(location.toURI())); } catch (Exception e) { // including NullPointerException and URISyntaxException throw new RuntimeException("Computation of Java test class-path failed", e); } } } return javaTestClassPath; } private SearchPath javaTestClassPath; //--------------------------------------------------------------------- public List getTestVMOptions() { if (testVMOpts == null) testVMOpts = Collections.emptyList(); return testVMOpts; } public void setTestVMOptions(List testVMOpts) { this.testVMOpts = Collections.unmodifiableList(new ArrayList<>(testVMOpts)); } private List testVMOpts; /** * Returns the set of VM options each prefixed by -J, as required by JDK tools. * @return the set of VM options */ public List getTestToolVMOptions() { List testToolVMOpts = new ArrayList<>(); for (String s: getTestVMOptions()) testToolVMOpts.add("-J" + s); return Collections.unmodifiableList(testToolVMOpts); } /** * Returns the set of VM options and Java options, for use by the java command. * @return the set of VM and Java options */ public List getTestVMJavaOptions() { if ((testVMOpts == null || testVMOpts.isEmpty()) && nativeDir == null) return getTestJavaOptions(); if ((testJavaOpts == null || testJavaOpts.isEmpty()) && nativeDir == null) return getTestVMOptions(); List opts = new ArrayList<>(); opts.addAll(getTestVMOptions()); opts.addAll(getTestJavaOptions()); if (nativeDir != null) opts.add("-Djava.library.path=" + nativeDir.toAbsolutePath()); return Collections.unmodifiableList(opts); } //--------------------------------------------------------------------- public List getTestCompilerOptions() { if (testCompilerOpts == null) testCompilerOpts = Collections.emptyList(); return testCompilerOpts; } public void setTestCompilerOptions(List testCompilerOpts) { this.testCompilerOpts = Collections.unmodifiableList(new ArrayList<>(testCompilerOpts)); } private List testCompilerOpts; //--------------------------------------------------------------------- public List getTestJavaOptions() { if (testJavaOpts == null) testJavaOpts = Collections.emptyList(); return testJavaOpts; } public void setTestJavaOptions(List testJavaOpts) { this.testJavaOpts = Collections.unmodifiableList(new ArrayList<>(testJavaOpts)); } private List testJavaOpts; //--------------------------------------------------------------------- public List getTestDebugOptions() { if (testDebugOpts == null) testDebugOpts = Collections.emptyList(); return testDebugOpts; } public void setTestDebugOptions(List testJavaOpts) { this.testDebugOpts = Collections.unmodifiableList(new ArrayList<>(testJavaOpts)); } private List testDebugOpts; //--------------------------------------------------------------------- List getRetainArgs() { return retainArgs; } public void setRetainArgs(List retainArgs) { retainStatusSet.clear(); if (retainArgs == null || retainArgs.contains("lastRun")) { // equivalent to "none" retainFilesPattern = null; return; } else { this.retainArgs = Collections.unmodifiableList(new ArrayList<>(retainArgs)); } StringBuilder sb = new StringBuilder(); for (String arg: retainArgs) { if (arg.equals("all")) { retainStatusSet.add(Status.PASSED); retainStatusSet.add(Status.FAILED); retainStatusSet.add(Status.ERROR); } else if (arg.equals("pass")) { retainStatusSet.add(Status.PASSED); } else if (arg.equals("fail")) { retainStatusSet.add(Status.FAILED); } else if (arg.equals("error")) { retainStatusSet.add(Status.ERROR); } else if (arg.equals("none")) { // can only appear by itself // no further action required } else if (arg.length() > 0) { if (sb.length() > 0) sb.append("|"); boolean inQuote = false; for (int i = 0; i < arg.length(); i++) { char c = arg.charAt(i); switch (c) { case '*': if (inQuote) { sb.append("\\E"); inQuote = false; } sb.append(".*"); break; default: if (!inQuote) { sb.append("\\Q"); inQuote = true; } sb.append(c); break; } } if (inQuote) sb.append("\\E"); } } retainFilesPattern = (sb.length() == 0 ? null : Pattern.compile(sb.toString())); } public boolean isRetainEnabled() { return (retainArgs != null); } public Set getRetainStatus() { return retainStatusSet; } public Pattern getRetainFilesPattern() { return retainFilesPattern; } //--------------------------------------------------------------------- public void setReportDir(Path reportDir) { this.reportDir = Objects.requireNonNull(reportDir); } public Path getReportDir() { return reportDir; } private Path reportDir; //--------------------------------------------------------------------- public void setExclusiveLock(Path exclusiveLock) { this.exclusiveLock = Objects.requireNonNull(exclusiveLock); } public Path getExclusiveLock() { return exclusiveLock; } private Path exclusiveLock; //--------------------------------------------------------------------- public void setNativeDir(Path nativeDir) { this.nativeDir = nativeDir; } public Path getNativeDir() { return nativeDir; } private Path nativeDir; //--------------------------------------------------------------------- public void setTimeoutHandler(String timeoutHandlerClassName) { this.timeoutHandlerClassName = Objects.requireNonNull(timeoutHandlerClassName); } String getTimeoutHandler() { return timeoutHandlerClassName; } private String timeoutHandlerClassName; //--------------------------------------------------------------------- void setTimeoutHandlerPath(String timeoutHandlerPath) { Objects.requireNonNull(timeoutHandlerPath); this.timeoutHandlerPath = new ArrayList<>(); for (String f: timeoutHandlerPath.split(File.pathSeparator)) { if (f.length() > 0) { this.timeoutHandlerPath.add(Path.of(f)); } } } public void setTimeoutHandlerPath(List timeoutHandlerPath) { this.timeoutHandlerPath = Objects.requireNonNull(timeoutHandlerPath); } List getTimeoutHandlerPath() { return timeoutHandlerPath; } private List timeoutHandlerPath; //--------------------------------------------------------------------- public void setTimeoutHandlerTimeout(long timeout) { this.timeoutHandlerTimeout = timeout; } private void setTimeoutHandlerTimeout(String timeout) { this.timeoutHandlerTimeout = Long.parseLong(timeout); } long getTimeoutHandlerTimeout() { return timeoutHandlerTimeout; } private long timeoutHandlerTimeout; //--------------------------------------------------------------------- public void setTestThreadFactory(String testThreadFactory) { this.testThreadFactory = testThreadFactory; } public String getTestThreadFactory() { return testThreadFactory; } private String testThreadFactory; public void setTestThreadFactoryPath(String testThreadFactoryPath) { this.testThreadFactoryPath = testThreadFactoryPath; } public String getTestThreadFactoryPath() { return testThreadFactoryPath; } private String testThreadFactoryPath; //--------------------------------------------------------------------- public void setMatchLists(Path[] files) { this.matchLists = List.of(files); } public List getMatchLists() { return Collections.unmodifiableList(matchLists); } private List matchLists; //--------------------------------------------------------------------- public void setUseWindowsSubsystemForLinux(boolean useWindowsSubsystemForLinux) { this.useWindowsSubsystemForLinux = useWindowsSubsystemForLinux; } public boolean useWindowsSubsystemForLinux() { return useWindowsSubsystemForLinux; } private boolean useWindowsSubsystemForLinux; //--------------------------------------------------------------------- public void setTestQueries(List testQueries) { this.testQueries = testQueries; } public List getTestQueries() { return testQueries; } /** * Returns the query component for a given test, if one was specified, * or null if there is no query component for this test. * * @param test the name of the test * @return the query component associated with this test, or null */ public String getTestQuery(String test) { // There are two common cases: // 1. any number of tests are being run, none of which have queries, or // 2. a single test is being run, which has query. // As such, it is probably not worth parsing testQueries into a map. if (testQueries != null) { for (String tq : testQueries) { int sep = tq.indexOf("?"); if (test.equals(tq.substring(0, sep))) { return tq.substring(sep + 1); } } } return null; } private List testQueries; //--------------------------------------------------------------------- public Pattern getRefIgnoreLinesPattern() { if (refIgnoreLinesPattern == UNSET_PATTERN) { String refIgnoreLines = System.getenv("JTREG_REF_IGNORE_LINES"); String re; if (refIgnoreLines != null) { // User-specified list of regular expressions for lines to ignore in golden file comparison. re = Arrays.stream(refIgnoreLines.trim().split("\\s+")) .map(s -> "(" + s + ")") .collect(Collectors.joining("|")); } else { // Default regular expressions, based on VM warnings when specific powerful VM options are set. // Override these by setting JTREG_REF_IGNORE_LINES to either empty or alternative regex list Map envVars = getEnvVars(); re = Stream.of("JAVA_TOOL_OPTIONS", "_JAVA_OPTIONS") .filter(envVars::containsKey) .map(e -> "(Picked up " + e + ":.*)") .collect(Collectors.joining("|")); } try { refIgnoreLinesPattern = re.isEmpty() ? null : Pattern.compile(re); } catch (PatternSyntaxException e) { refIgnoreLinesPattern = null; throw e; } } return refIgnoreLinesPattern; } private static final Pattern UNSET_PATTERN = Pattern.compile(""); private Pattern refIgnoreLinesPattern = UNSET_PATTERN; //--------------------------------------------------------------------- // Ideally, this method would be better on a "shared execution context" object public TimeoutHandlerProvider getTimeoutHandlerProvider() throws MalformedURLException { if (timeoutHandlerProvider == null) { timeoutHandlerProvider = new TimeoutHandlerProvider(); timeoutHandlerProvider.setClassName(timeoutHandlerClassName); if (timeoutHandlerPath != null && !timeoutHandlerPath.isEmpty()) timeoutHandlerProvider.setClassPath(timeoutHandlerPath); if (timeoutHandlerTimeout != -1) timeoutHandlerProvider.setTimeout(timeoutHandlerTimeout); } return timeoutHandlerProvider; } private TimeoutHandlerProvider timeoutHandlerProvider; //--------------------------------------------------------------------- /** * Returns a map containing the properties that are passed to all tests and * other VBMs started by jtreg. * * @return the map */ // Ideally, this method would be better on a "shared execution context" object public Map getBasicTestProperties() { if (basicTestProperties == null) { Map map = new LinkedHashMap<>(); put(map, "test.vm.opts", getTestVMOptions(), v -> StringUtils.join(v, " ")); put(map, "test.tool.vm.opts", getTestToolVMOptions(), v -> StringUtils.join(v, " ")); put(map, "test.compiler.opts", getTestCompilerOptions(), v -> StringUtils.join(v, " ")); put(map, "test.java.opts", getTestJavaOptions(), v -> StringUtils.join(v, " ")); put(map, "test.jdk", getTestJDK(), JDK::getAbsolutePath); put(map, "compile.jdk", getCompileJDK(), JDK::getAbsolutePath); put(map, "test.timeout.factor", getTimeoutFactor(), String::valueOf); put(map, "test.nativepath", getNativeDir(), p -> p.toAbsolutePath().toString()); put(map, "test.root", getTestSuite().getRootDir(), File::getAbsolutePath); basicTestProperties = map; } return basicTestProperties; } private void put(Map map, String name, T value, Function toString) { if (value != null) { map.put(name, toString.apply(value)); } } private Map basicTestProperties; //--------------------------------------------------------------------- public OS getTestOS() { // In general, and particularly when running tests, the testJDK should always be set. // But in some testing and reporting situations, it may not be. In these cases, // we default to the current platform. JDK jdk = getTestJDK(); if (jdk == null) { return OS.current(); } else { try { return OS.forProps(testJDK.getProperties(this, logger)); } catch (JDK.Fault f) { // If it was going to happen, this exception would have been thrown // and caught early on, during Tool.createParameters; by now, the // properties should always be available. throw new IllegalStateException(f); } } } //--------------------------------------------------------------------- private List retainArgs; private final Set retainStatusSet = new HashSet<>(4); private Pattern retainFilesPattern; private static final I18NResourceBundle i18n = I18NResourceBundle.getBundleForClass(RegressionParameters.class); } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/config/RegressionTestFinder.java000066400000000000000000001175261461415321300324110ustar00rootroot00000000000000/* * Copyright (c) 1997, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.config; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.StreamTokenizer; import java.lang.reflect.Field; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.sun.javatest.TestDescription; import com.sun.javatest.TestResult; import com.sun.javatest.TestSuite; import com.sun.javatest.finder.CommentStream; import com.sun.javatest.finder.HTMLCommentStream; import com.sun.javatest.finder.JavaCommentStream; import com.sun.javatest.finder.ShScriptCommentStream; import com.sun.javatest.finder.TagTestFinder; import com.sun.javatest.regtest.agent.Flags; import com.sun.javatest.regtest.exec.Action; import com.sun.javatest.regtest.util.StringUtils; import com.sun.javatest.util.I18NResourceBundle; /** * This is a specific implementation of the TagTestFinder which is to be used * for JDK regression testing. It follows the test-tag specifications as given * in http://openjdk.org/jtreg/tag-spec.txt. * * A test description consists of a single block comment in either Java files * or shell-script files. A file may contain multiple test descriptions. * * @see com.sun.javatest.TestFinder * @see com.sun.javatest.finder.TagTestFinder */ public final class RegressionTestFinder extends TagTestFinder { /** * Constructs the list of file names to exclude for pruning in the search * for files to examine for test descriptions. This constructor also sets * the allowable comment formats. * * @param properties the test suite properties manager * @param errHandler a handler for error messages */ public RegressionTestFinder(TestProperties properties, ErrorHandler errHandler) { setErrorHandler(errHandler); this.properties = properties; this.checkBugID = properties.checkBugID; Set rootValidKeys = properties.validKeys; validTagNames = getValidTagNames(rootValidKeys != null); exclude(excludeNames); addExtension(".sh", ShScriptCommentStream.class); addExtension(".html", HTMLCommentStream.class); addExtension(".jasm", JavaCommentStream.class); addExtension(".jcod", JavaCommentStream.class); baseContext = RegressionContext.getDefault(); } @SuppressWarnings("unchecked") Set getAllowedExtensions() { return ((Map) getField("extensionTable")).keySet(); } @SuppressWarnings("unchecked") Set getIgnoredDirectories() { return ((Map) getField("excludeList")).keySet(); } private Object getField(String name) { try { Field f = TagTestFinder.class.getDeclaredField(name); try { f.setAccessible(true); return f.get(this); } finally { f.setAccessible(false); } } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { e.printStackTrace(System.err); return null; } } @Override protected void setRoot(File testSuiteRoot) throws Fault { super.setRoot(canon(testSuiteRoot)); } @Override protected void scanFile(File file) { if (traceFinder) { System.err.println("RegressionTestFinder: reading " + file); } try { File tngRoot = properties.getTestNGRoot(file); if (tngRoot != null) { scanTestNGFile(tngRoot, file); } else { File junitRoot = properties.getJUnitRoot(file); if (junitRoot != null) { scanJUnitFile(junitRoot, file); } else { //super.scanFile(file); modifiedScanFile(file); } } } catch (TestSuite.Fault e) { error(i18n, "finder.cant.read.test.properties", e.getMessage()); } } /** * Scan a file, looking for comments and in the comments, for test * description data. * @param file The file to scan */ // This is a proposed new version for TagTestFinder.scanFile. // The significant change is to look ahead for any additional // comments when deciding whether or not to set an id for the // test description. With this change, if a test file contains // more than one test description, all test descriptions are // given a unique id; previously, the first test description did not. // The externally visible effect is that putting the name of the // file on the command line explicitly will cause *all* the // tests in that file to be run, and not just the first. protected void modifiedScanFile(File file) { I18NResourceBundle super_i18n; boolean super_fastScan; try { Field i18nField = TagTestFinder.class.getDeclaredField("i18n"); i18nField.setAccessible(true); super_i18n = (I18NResourceBundle) i18nField.get(this); Field fastScanField = TagTestFinder.class.getDeclaredField("fastScan"); fastScanField.setAccessible(true); super_fastScan = (boolean) fastScanField.get(this); } catch (NoSuchFieldException | IllegalAccessException ex) { throw new Error(ex); } int testDescNumber = 0; String name = file.getName(); int dot = name.indexOf('.'); if (dot == -1) return; String extn = name.substring(dot); Class csc = getClassForExtension(extn); if (csc == null) { error(super_i18n, "tag.noParser", file, extn); return; } CommentStream cs; try { cs = csc.getDeclaredConstructor().newInstance(); } catch (ReflectiveOperationException e) { error(super_i18n, "tag.cantCreateClass", csc.getName(), extn); return; } try { LineCounterBufferedReader r = new LineCounterBufferedReader(new FileReader(file)); cs.init(r); if (super_fastScan) cs.setFastScan(true); String comment = cs.readComment(); int commentLine = r.lineNumber; while (comment != null) { Map tagValues = parseComment(comment, file); // Look ahead to see if there are more comments String nextComment = cs.readComment(); int nextCommentLine = r.lineNumber; if (!tagValues.isEmpty()) { if (tagValues.get("id") == null) { // if there are more comments to come, or if there have already // been additional comments, set an explicit id for each set of tags if ((nextComment != null && nextComment.trim().startsWith("@test")) || testDescNumber != 0) { String test = tagValues.get("test"); Matcher m; String id = (test != null && (m = Pattern.compile("id=(?[A-Za-z0-9-_]+)\\b.*").matcher(test)).matches()) ? m.group("id") : "id" + testDescNumber; tagValues.put("id", id); } testDescNumber++; } // The "test" marker can now be removed so that we don't waste // space unnecessarily. We need to do the remove *after* the // isEmpty() check because of the potential to interfere with // defaults based on file extension. (i.e. The TD /* @test */ // still needs to evaluate to a valid test description.) tagValues.remove("test"); foundTestDescription(tagValues, file, commentLine); } comment = nextComment; commentLine = nextCommentLine; } } catch (FileNotFoundException e) { error(super_i18n, "tag.cantFindFile", file); } catch (IOException e) { error(super_i18n, "tag.ioError", file); } finally { try { cs.close(); } catch (IOException e) { } } } private static class LineCounterBufferedReader extends BufferedReader { int lineNumber; LineCounterBufferedReader(FileReader r) { super(r); lineNumber = 1; } @Override public int read() throws IOException { int ch = super.read(); checkNewline(ch); return ch; } @Override public String readLine() throws IOException { String line = super.readLine(); lineNumber++; return line; } @Override public int read(char[] buf, int offset, int length) throws IOException { int n = super.read(buf, offset, length); for (int i = offset; i < offset + n; i++) { checkNewline(buf[i]); } return n; } private void checkNewline(int ch) { if (ch == '\n') { lineNumber++; } } } protected void scanTestNGFile(File tngRoot, File file) throws TestSuite.Fault { if (isTestNGTest(file)) { scanFile(tngRoot, file, "testngClass", true); } } protected void scanJUnitFile(File junitRoot, File file) throws TestSuite.Fault { if (isJUnitTest(file)) { scanFile(junitRoot, file, "junitClass", false); } } protected void scanFile(File junitRoot, File file, String classPropertyName, boolean setImportsJUnit) throws TestSuite.Fault { Map tagValues; PackageImportParser p = new PackageImportParser(junitRoot, file); p.parse(); String className = p.inferClassName(); try (BufferedReader in = new BufferedReader(new FileReader(file))) { tagValues = readComments(file, in); if (tagValues == null) { tagValues = new HashMap<>(); // could read more of file looking for annotations like @Test, @Factory // to guess whether this is really a test file or not } tagValues.put("packageRoot", getRootDir().toURI().relativize(junitRoot.toURI()).getPath()); if (className == null) { tagValues.put("error", "cannot determine class name"); } else { tagValues.put(classPropertyName, className); } if (setImportsJUnit && p.importsJUnit) { tagValues.put("importsJUnit", "true"); } Set libDirs = properties.getLibDirs(file); if (libDirs != null && !libDirs.isEmpty()) { tagValues.put("library", StringUtils.join(libDirs, " ")); } foundTestDescription(tagValues, file, /*line*/0); } catch (IOException e) { error(i18n, "finder.ioError", file); } } private class PackageImportParser { private final File rootDir; private final File file; String packageName; boolean importsJUnit; PackageImportParser(File rootDir, File file) { this.rootDir = rootDir; this.file = file; } void parse() { try (BufferedReader in = new BufferedReader(new FileReader(file))) { StreamTokenizer st = new StreamTokenizer(in); st.resetSyntax(); st.slashSlashComments(true); st.slashStarComments(true); st.wordChars('a', 'z'); st.wordChars('A', 'Z'); st.wordChars('$', '$'); st.wordChars('_', '_'); // the following are treated as word characters to simplify parsing // package names and imports as a single token st.wordChars('0', '9'); st.wordChars('.', '.'); st.wordChars('*', '*'); st.whitespaceChars(0, ' '); st.eolIsSignificant(false); // parse package and import statements int t; while ((t = st.nextToken()) != StreamTokenizer.TT_EOF) { if (t != StreamTokenizer.TT_WORD) return; switch (st.sval) { case "package": if (st.nextToken() != StreamTokenizer.TT_WORD) return; packageName = st.sval; if (st.nextToken() != ';') return; break; case "import": t = st.nextToken(); if (t == StreamTokenizer.TT_WORD && st.sval.equals("static")) { t = st.nextToken(); } if (t == StreamTokenizer.TT_WORD && st.sval.startsWith("org.junit")) { importsJUnit = true; return; // no need to read further } if (st.nextToken() != ';') return; } } } catch (IOException e) { error(i18n, "finder.ioError", file); } } String inferClassName() { String path = rootDir.toURI().relativize(file.toURI()).getPath(); String fn = file.getName(); String cn = fn.replace(".java", ""); String pkg_fn = (packageName == null) ? file.getName() : packageName.replace('.', '/') + "/" + fn; if (path.equalsIgnoreCase(pkg_fn)) { return (packageName == null) ? cn : packageName + "." + cn; } else if (path.toLowerCase().endsWith("/" + pkg_fn.toLowerCase())) { String mn = path.substring(0, path.length() - pkg_fn.length()); return mn + ((packageName == null) ? cn : packageName + "." + cn); } else { return null; } } } private Map readComments(File file, BufferedReader in) throws IOException { CommentStream cs = new JavaCommentStream(); cs.init(in); cs.setFastScan(true); Map tagValues = null; String comment; int index = 1; while ((comment = cs.readComment()) != null) { Map tv = parseComment(comment, file); if (tv.isEmpty()) continue; if (tagValues == null) { tagValues = tv; } else { tv.put("error", PARSE_MULTIPLE_COMMENTS_NOT_ALLOWED); tv.put("id", String.valueOf(index++)); foundTestDescription(tv, file, /*line*/0); } // The "test" marker can now be removed so that we don't waste // space unnecessarily. We need to do the remove *after* the // isEmpty() check because of the potential to interfere with // defaults based on file extension. (i.e. The TD /* @test */ // still needs to evaluate to a valid test description.) tagValues.remove("test"); } return tagValues; } protected boolean isTestNGTest(File file) { // for now, ignore comments and annotations, and // assume *.java is a test return isClassOrInterfaceFile(file); } protected boolean isJUnitTest(File file) { // for now, ignore comments and annotations, and // assume *.java is a test return isClassOrInterfaceFile(file); } private boolean isClassOrInterfaceFile(File file) { String name = file.getName(); return name.endsWith(".java") && !name.equals("module-info.java") && !name.equals("package-info.java"); } private File canon(File f) { try { return f.getCanonicalFile(); } catch (IOException e) { return new File(f.getAbsoluteFile().toURI().normalize()); } } protected Map normalize(Map tagValues) { Map newTagValues = new HashMap<>(); String fileName = getCurrentFile().getName(); String baseName = fileName.substring(0, fileName.lastIndexOf(".")); boolean isTestNG = tagValues.containsKey("testngClass"); boolean isJUnit = tagValues.containsKey("junitClass"); // default values newTagValues.put("title", " "); newTagValues.put("source", fileName); if (isTestNG) { if (tagValues.get("run") != null) { tagValues.put("error", PARSE_BAD_RUN); } String className = tagValues.get("testngClass"); newTagValues.put("run", Action.REASON_ASSUMED_ACTION + " testng " + className + LINESEP); } else if (isJUnit) { if (tagValues.get("run") != null) { tagValues.put("error", PARSE_BAD_RUN); } String className = tagValues.get("junitClass"); newTagValues.put("run", Action.REASON_ASSUMED_ACTION + " junit " + className + LINESEP); } else if (fileName.endsWith(".sh")) { newTagValues.put("run", Action.REASON_ASSUMED_ACTION + " shell " + fileName + LINESEP); } else if (fileName.endsWith(".java")) { // we have a ".java" file newTagValues.put("run", Action.REASON_ASSUMED_ACTION + " main " + baseName + LINESEP); } else { // we have a ".html" file newTagValues.put("run", Action.REASON_ASSUMED_ACTION + " applet " + fileName + LINESEP); } // translate between JDK tags and JavaTest tags; for required // JavaTest fields, make sure that we make a reasonable assumption for (Map.Entry e: tagValues.entrySet()) { String name = e.getKey(); String value = e.getValue(); switch (name) { case "summary": // the title is the first sentence of the provided summary name = "title"; int pos = 0; loop: while (true) { pos = value.indexOf(".", pos); if (pos == -1 || pos + 1 == value.length()) break; switch (value.charAt(pos + 1)) { case ' ': case '\n': case '\r': case '\t': case '\f': case '\b': value = value.substring(0, pos + 1); break loop; } pos++; } break; case "bug": case "key": { // force some keywords name = "keywords"; String oldValue = newTagValues.get("keywords"); if (oldValue != null) value = oldValue + " " + value; break; } case "test": { // TagTestFinder.scanFile() removes the "test" name/value pair, // so I don't think that we'll ever get here. 3/13 // If we run into an @test, we have a regression test. // Add "regtest" to the list of keywords. The script // will be triggered off this keyword. name = "keywords"; String oldValue = newTagValues.get("keywords"); if (oldValue != null) value = oldValue + " regtest"; else value = "regtest"; break; } default: break; } // System.out.println("--- NAME: " + name + " VALUE: " + value); newTagValues.put(name, value); } String value = newTagValues.get("run"); // force more key words based on actions Set keywords = split(newTagValues.get("keywords"), "\\s+"); if (match(value, OTHERVM_OPTION) || match(value, BOOTCLASSPATH_OPTION)) keywords.add("othervm"); if (match(value, MANUAL_OPTION)) keywords.add("manual"); if (match(value, NATIVE_OPTION)) keywords.add("native"); if (match(value, SHELL_ACTION)) keywords.add("shell"); if (match(value, JUNIT_ACTION) || isJUnit) keywords.add("junit"); if (match(value, TESTNG_ACTION) || isTestNG) keywords.add("testng"); if (match(value, DRIVER_ACTION)) keywords.add("driver"); if (match(value, IGNORE_ACTION)) keywords.add("ignore"); newTagValues.put("keywords", StringUtils.join(keywords, " ")); if (rejectTrailingBuild) { int sep = value.lastIndexOf(LINESEP, value.length() - 1 - LINESEP.length()); // ignore final LINESEP String lastLine = value.substring(sep == -1 ? 0 : sep + LINESEP.length()); if (lastLine.startsWith(Action.REASON_USER_SPECIFIED + " build")) { newTagValues.put("error", PARSE_RUN_ENDS_WITH_BUILD); } } int maxTimeout = -1; // The following pattern is slightly sloppy since it runs the risk of // false positives in the args to a test; if necessary the pattern could // require matching on the possible action names as well. Pattern p = Pattern.compile("/timeout=([0-9]+)(?:/| )"); Matcher m = p.matcher(value); while (m.find()) { int t = Integer.parseInt(m.group(1)); if (t == 0) { // zero means no-limit maxTimeout = 0; break; } if (t > maxTimeout) maxTimeout = t; } if (maxTimeout > 0) newTagValues.put("maxTimeout", String.valueOf(maxTimeout)); try { String modules = newTagValues.get(MODULES); if (modules == null || modules.isEmpty()) { Set defaultModules = properties.getModules(getCurrentFile()); if (defaultModules != null && !defaultModules.isEmpty()) { processModules(newTagValues, defaultModules); } } String enablePreview = newTagValues.get(ENABLE_PREVIEW); if (enablePreview == null) { boolean ep = properties.getEnablePreview(getCurrentFile()); if (ep) { newTagValues.put(ENABLE_PREVIEW, "true"); } } } catch (TestSuite.Fault e) { error(i18n, "finder.cant.read.test.properties", e.getMessage()); } /* for (Map.Entry e: newTagValues.entrySet()) { System.out.println("NAME: " + e.getKey() + " VALUE: " + e.getValue()); // if (name.equals("keywords")) // System.out.println(currFile + " " + "`" + value + "'"); } */ return newTagValues; } private static boolean match(CharSequence cs, Pattern p) { return p.matcher(cs).matches(); } private Set split(String s, String regex) { Set result = new LinkedHashSet<>(); if (s != null) { result.addAll(List.of(s.split(regex))); } return result; } /** * Make sure that the provided name-value pair is of the proper format as * described in the tag-spec. * * @param entries The map of the entries being read * @param name The name of the entry that has been read * @param value The value of the entry that has been read */ protected void processEntry(Map entries, String name, String value) { // translate the shorthands into run actions if (name.startsWith(COMPILE) || name.startsWith(CLEAN) || name.startsWith(BUILD) || name.startsWith(IGNORE)) { value = name + " " + value; name = RUN; } try { switch (name) { case RUN: processRun(entries, value); break; case BUG: processBug(entries, value); break; case REQUIRES: processRequires(entries, value); break; case KEY: processKey(entries, value); break; case MODULES: processModules(entries, value); break; case LIBRARY: processLibrary(entries, value); break; case COMMENT: // no-op break; case ENABLE_PREVIEW: processEnablePreview(entries, value); break; default: if (!validTagNames.contains(name)) { parseError(entries, PARSE_TAG_BAD + name); } else { entries.put(name, value); } } } catch (TestSuite.Fault e) { reportError(entries, e.getMessage()); } } @Override protected void foundTestDescription(TestDescription td) { String wrp = TestResult.getWorkRelativePath(td); TestDescription other = paths.get(wrp); if (other != null && !td.getRootRelativeURL().equals(other.getRootRelativeURL())) { error(i18n, "finder.jtrClash", td.getFile(), other.getFile()); return; } super.foundTestDescription(td); paths.put(wrp, td); } Map paths = new HashMap<>(); //-----internal routines---------------------------------------------------- //---------- parsing ------------------------------------------------------- private void parseError(Map tagValues, String value) { // TODO: The use of "Exception" in the following message is // temporarily retained for backward compatibility. // "Error" would be a better word. reportError(tagValues, "Parse Exception: " + value); } private void reportError(Map tagValues, String value) { // for now, just record first error tagValues.putIfAbsent(ERROR, value); } /** * Create the "run" action entry by adding a reason code to the * user-provided action. Each action is separated by LINESEP. * * @param tagValues The map of all of the current tag values. * @param value The value of the entry currently being processed. */ private void processRun(Map tagValues, String value) { String oldValue = tagValues.get(RUN); StringBuilder sb = new StringBuilder(); if (oldValue != null) sb.append(oldValue); sb.append(Action.REASON_USER_SPECIFIED) .append(" ") .append(value) .append(LINESEP); tagValues.put(RUN, sb.toString()); } /** * Verify that all bugs are properly formatted. * Each provided bugid must match one of the following patterns: * Sun bug number: 7 digits * OpenJDK JIRA number: 7 digits or PROJECTNAME- 7 digits * Oracle internal bug number: 8 digits beginning 14 * * @param tagValues The map of all of the current tag values. * @param value The value of the entry currently being processed. */ private void processBug(Map tagValues, String value) { if (value.trim().length() == 0) { parseError(tagValues, PARSE_BUG_EMPTY); return; } StringBuilder newValue = new StringBuilder(); if (tagValues.get(BUG) != null) newValue.append(tagValues.get(BUG)); for (String bugid : StringUtils.splitWS(value)) { // bugid checking can be switched on and off with an // environment var. that the testsuite finds if (checkBugID && !bugIdPattern.matcher(bugid).matches()) { parseError(tagValues, PARSE_BUG_INVALID + bugid); continue; } if (newValue.length() > 0) newValue.append(" "); newValue.append("bug").append(bugid); } if (newValue.length() > 0) tagValues.put(BUG, newValue.toString()); } private static final Pattern bugIdPattern = Pattern.compile("(([A-Z]+-)?[0-9]{7})|(14[0-9]{6})"); /** * Validate @requires, and combine multiple instances. * * @param tagValues The map of all of the current tag values. * @param value The value of the entry currently being processed. */ private void processRequires(Map tagValues, String value) throws TestSuite.Fault { if (value.trim().length() == 0) { parseError(tagValues, PARSE_REQUIRES_EMPTY); return; } try { final Set validPropNames = properties.getValidRequiresProperties(getCurrentFile()); Expr.Context c = new RegressionContext(baseContext, validPropNames); Expr.parse(value, c); } catch (Expr.Fault f) { parseError(tagValues, PARSE_REQUIRES_SYNTAX + f.getMessage()); return; } tagValues.merge(REQUIRES, value, (a, b) -> "(" + a + ") & (" + b + ")"); } /** * Verify that the provided set of keys are allowed for the current * test-suite. The set of keys is stored in the system property * {@code env.regtest.key}. * * @param tagValues The map of all of the current tag values. * @param value The value of the entry currently being processed. */ private void processKey(Map tagValues, String value) throws TestSuite.Fault { if (value.trim().length() == 0) { parseError(tagValues, PARSE_KEY_EMPTY); return; } // make sure that the provided keys are all valid Set validKeys = properties.getValidKeys(getCurrentFile()); StringBuilder newValue = new StringBuilder(); for (String key: StringUtils.splitWS(value)) { String k = key.replace("-", "_"); if (!validKeys.contains(k)) { parseError(tagValues, PARSE_KEY_BAD + key); continue; } if (newValue.length() > 0) newValue.append(" "); newValue.append(k); } if (newValue.length() > 0) tagValues.put(KEY, newValue.toString()); } /** * Analyse the contents of @modules. * @param tagValues The map of all of the current tag values. * @param value The value of the entry currently being processed. */ private void processModules(Map tagValues, String value) throws TestSuite.Fault { if (value.trim().length() == 0) { parseError(tagValues, PARSE_MODULES_EMPTY); return; } processModules(tagValues, List.of(value.trim().split("\\s+"))); } private void processModules(Map tagValues, Collection modules) { for (String word : modules) { try { Modules.Entry m = Modules.parse(word); } catch (Modules.Fault f) { parseError(tagValues, PARSE_BAD_MODULE + f.getMessage()); return; } } String oldValue = tagValues.get(MODULES); String value = StringUtils.join(modules, " "); if (oldValue == null) tagValues.put(MODULES, value); else tagValues.put(MODULES, oldValue + " " + value); } /** * Create the library-directory list. Path names are prepended left to * right. * * @param tagValues The map of all of the current tag values. * @param value The value of the entry currently being processed. */ private void processLibrary(Map tagValues, String value) { String newValue; if (tagValues.get(RUN) == null) { // we haven't seen a "run" action yet if (value.trim().length() != 0) { // multiple library tags allowed, prepend the new stuff String oldValue = tagValues.get(LIBRARY); if (oldValue != null) newValue = value.trim() + " " + oldValue; else newValue = value.trim(); tagValues.put(LIBRARY, newValue); } else { // found an empty library tag parseError(tagValues, PARSE_LIB_EMPTY); } } else { // found library tag after the first @run tag parseError(tagValues, PARSE_LIB_AFTER_RUN); } } private void processEnablePreview(Map tagValues, String value) { if (value.isEmpty()) { tagValues.put(ENABLE_PREVIEW, "true"); } else { String v = value.trim(); switch (v) { case "false": case "true": tagValues.put(ENABLE_PREVIEW, v); break; default: parseError(tagValues, PARSE_INVALID_ENABLE_PREVIEW + v); } } } private Set getValidTagNames(boolean allowKey) { Set tags = new HashSet<>(); // JDK specific tags tags.add(TEST); tags.add(BUG); tags.add(SUMMARY); tags.add(AUTHOR); tags.add(LIBRARY); tags.add(MODULES); tags.add(CLEAN); tags.add(COMPILE); tags.add(IGNORE); tags.add(RUN); tags.add(BUILD); tags.add(REQUIRES); tags.add(COMMENT); tags.add(ENABLE_PREVIEW); // @key allowed only if TEST.ROOT contains a non-empty entry for // "key". This is handled by the testsuite object. if (allowKey) { tags.add(KEY); } return tags; } //----------misc statics---------------------------------------------------- public static final String TEST = "test"; public static final String AUTHOR = "author"; public static final String BUG = "bug"; public static final String BUILD = "build"; public static final String CLEAN = "clean"; public static final String COMPILE = "compile"; public static final String ENABLE_PREVIEW = "enablePreview"; public static final String ERROR = "error"; public static final String IGNORE = "ignore"; public static final String KEY = "key"; public static final String LIBRARY = "library"; public static final String MODULES = "modules"; public static final String REQUIRES = "requires"; public static final String RUN = "run"; public static final String SUMMARY = "summary"; public static final String COMMENT = "comment"; private static final String LINESEP = System.getProperty("line.separator"); static final String[] excludeNames = { ".hg", ".git" }; // These are all the error messages used in the finder. static final String PARSE_TAG_BAD = "Invalid tag: ", PARSE_BUG_EMPTY = "No value provided for `@bug'", PARSE_BUG_INVALID = "Invalid or unrecognized bugid: ", PARSE_KEY_EMPTY = "No value provided for `@key'", PARSE_KEY_BAD = "Invalid key: ", PARSE_LIB_EMPTY = "No value provided for `@library'", PARSE_LIB_AFTER_RUN = "`@library' must appear before first action tag", PARSE_MODULES_EMPTY = "No values provided for @modules", PARSE_BAD_MODULE = "Invalid item in @modules: ", PARSE_BAD_RUN = "Explicit action tag not allowed", PARSE_REQUIRES_EMPTY = "No expression for @requires", PARSE_REQUIRES_SYNTAX = "Syntax error in @requires expression: ", PARSE_RUN_ENDS_WITH_BUILD = "No action after @build", PARSE_MULTIPLE_COMMENTS_NOT_ALLOWED = "Multiple test descriptions not allowed", PARSE_INVALID_ENABLE_PREVIEW = "invalid value for @enablePreview: "; private static final Pattern BOOTCLASSPATH_OPTION = getOptionPattern("bootclasspath"), OTHERVM_OPTION = getOptionPattern("othervm"), MANUAL_OPTION = getOptionPattern("manual"), NATIVE_OPTION = getOptionPattern("native"), SHELL_ACTION = getActionPattern("shell"), JUNIT_ACTION = getActionPattern("junit"), TESTNG_ACTION = getActionPattern("testng"), DRIVER_ACTION = getActionPattern("driver"), IGNORE_ACTION = getActionPattern("ignore"); private static Pattern getActionPattern(String name) { return Pattern.compile("(?s).*(" + Action.REASON_USER_SPECIFIED + "|" + Action.REASON_ASSUMED_ACTION + ") \\Q" + name + "\\E\\b.*"); } private static Pattern getOptionPattern(String name) { return Pattern.compile("(?s).*/" + name + "[/= \t].*"); } //----------member variables------------------------------------------------ private final Set validTagNames; private final TestProperties properties; private final boolean checkBugID; private final RegressionContext baseContext; private static final I18NResourceBundle i18n = I18NResourceBundle.getBundleForClass(RegressionTestFinder.class); private static final boolean rejectTrailingBuild = !Boolean.getBoolean("javatest.regtest.allowTrailingBuild"); private static final boolean traceFinder = Flags.get("traceFinder"); } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/config/RegressionTestSuite.java000066400000000000000000000222251461415321300322620ustar00rootroot00000000000000/* * Copyright (c) 2000, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.config; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.lang.ref.SoftReference; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import com.sun.javatest.InterviewParameters; import com.sun.javatest.Script; import com.sun.javatest.TestDescription; import com.sun.javatest.TestEnvironment; import com.sun.javatest.TestFinder; import com.sun.javatest.TestSuite; import com.sun.javatest.WorkDirectory; import com.sun.javatest.regtest.exec.RegressionScript; import com.sun.javatest.regtest.tool.Version; import com.sun.javatest.util.BackupPolicy; import com.sun.javatest.util.I18NResourceBundle; import com.sun.javatest.regtest.tool.RegressionContextManager; public final class RegressionTestSuite extends TestSuite { static Map> cache; public static RegressionTestSuite open(File testSuiteRoot, TestFinder.ErrorHandler errHandler) throws Fault { if (cache == null) cache = new HashMap<>(); SoftReference ref = cache.get(testSuiteRoot); RegressionTestSuite ts = (ref == null) ? null : ref.get(); if (ts == null) { ts = new RegressionTestSuite(testSuiteRoot, errHandler); cache.put(testSuiteRoot, new SoftReference<>(ts)); } return ts; } /** * Creates a {@code RegressionTestSuite} object for the test suite identified by a given path. * @param testSuiteRoot the root directory of the test suite * @param errHandler a handler that can be used to report any problems encountered by * the test suite's test handler * @throws Fault if there are problems reading the {@code TEST.ROOT} file. */ public RegressionTestSuite(File testSuiteRoot, TestFinder.ErrorHandler errHandler) throws Fault { super(testSuiteRoot, createTSInfo(), RegressionTestSuite.class.getClassLoader()); properties = new TestProperties(getRootDir(), errHandler); this.errHandler = errHandler; setTestFinder(createTestFinder()); } private static Map createTSInfo() { Map map = new HashMap<>(); map.put(TestSuite.TM_CONTEXT_NAME, RegressionContextManager.class.getName()); return map; } @Override public String getName() { return getPath(); // better than nothing, could pick up name from TEST.ROOT } @Override protected TestFinder createTestFinder() throws Fault { try { TestFinder f = new RegressionTestFinder(properties, errHandler); f.init(new String[] { }, getRoot(), null); return f; } catch (TestFinder.Fault e) { throw new Error(); } } @Override public boolean getTestRefreshBehavior(int event) { switch (event) { case CLEAR_CHANGED_TEST: case DELETE_NONTEST_RESULTS: return true; default: return super.getTestRefreshBehavior(event); } } @Override public Script createScript(TestDescription td, String[] exclTestCases, TestEnvironment scriptEnv, WorkDirectory workDir, BackupPolicy backupPolicy) throws Fault { Script s = new RegressionScript(); // generic script init s.initTestDescription(td); s.initExcludedTestCases(exclTestCases); s.initTestEnvironment(scriptEnv); s.initWorkDir(workDir); s.initBackupPolicy(backupPolicy); s.initClassLoader(getClassLoader()); return s; } public interface ParametersFactory { RegressionParameters create(RegressionTestSuite ts) throws TestSuite.Fault; } private static ParametersFactory factory; public static void setParametersFactory(ParametersFactory factory) { RegressionTestSuite.factory = factory; } /** * {@inheritDoc} * * If no {@link #setParametersFactory(ParametersFactory) factory} has been set, * any errors that may be reported while using the {@link JDK} and related classes * will be written to {@link System#err}. */ @Override public RegressionParameters createInterview() throws TestSuite.Fault { try { return (factory != null) ? factory.create(this) // expected case : new RegressionParameters("regtest", this, System.err::println); // fallback } catch (InterviewParameters.Fault e) { throw new TestSuite.Fault(i18n, "suite.cantCreateInterview", e.getMessage()); } } @Override public URL[] getFilesForTest(TestDescription td) { Set urls = new LinkedHashSet<>(); // always start with the file containing the test description try { urls.add(td.getFile().toURI().toURL()); } catch (MalformedURLException e) { // ignore any bad URLs } try { RegressionParameters params = createInterview(); Set files = RegressionScript.getSourceFiles(params, td); for (File file: files) { try { urls.add(file.toURI().toURL()); } catch (MalformedURLException e) { } } } catch (Fault ignore) { } return urls.toArray(new URL[urls.size()]); } public GroupManager getGroupManager(PrintWriter out) throws IOException { GroupManager g = new GroupManager(out, getRootDir().toPath(), properties.getGroupFiles()); RegressionTestFinder tf = (RegressionTestFinder) getTestFinder(); g.setAllowedExtensions(tf.getAllowedExtensions()); g.setIgnoredDirectories(tf.getIgnoredDirectories()); return g; } // defined in JT Harness 4.2, needs to be overridden // because default impl broken for jtreg (NPE) @Override public boolean needServices() { return false; } public ExecMode getDefaultExecMode() { return properties.getDefaultExecMode(); } public boolean useBootClassPath(String rootRelativePath) throws TestSuite.Fault { return properties.useBootClassPath(new File(getRootDir(), rootRelativePath)); } public boolean useOtherVM(TestDescription td) throws TestSuite.Fault { return properties.useOtherVM(td.getFile()); } public boolean needsExclusiveAccess(TestDescription td) throws TestSuite.Fault { return properties.needsExclusiveAccess(td.getFile()); } public Version getRequiredVersion() { return properties.getRequiredVersion(); } public Set getLibDirs(TestDescription td) throws TestSuite.Fault { return properties.getLibDirs(td.getFile()); } public Set getLibBuildArgs(TestDescription td) throws TestSuite.Fault { return properties.getLibBuildArgs(td.getFile()); } public Set getExternalLibRoots(TestDescription td) throws TestSuite.Fault { return properties.getExternalLibs(td.getFile()); } public Set getDefaultModules(TestDescription td) throws TestSuite.Fault { return properties.getModules(td.getFile()); } public ExtraPropDefns getExtraPropDefns() { return properties.getExtraPropDefns(); } public int getMaxOutputSize(TestDescription td) throws TestSuite.Fault { return properties.getMaxOutputSize(td.getFile()); } public boolean getAllowSmartActionArgs(TestDescription td) throws TestSuite.Fault { return properties.getAllowSmartActionArgs(td.getFile()); } public boolean getEnablePreview(TestDescription td) throws TestSuite.Fault { return properties.getEnablePreview(td.getFile()); } private final TestFinder.ErrorHandler errHandler; private final TestProperties properties; private static final I18NResourceBundle i18n = I18NResourceBundle.getBundleForClass(RegressionTestSuite.class); } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/config/TestManager.java000066400000000000000000000667141461415321300305150ustar00rootroot00000000000000/* * Copyright (c) 1997, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.config; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.nio.file.Files; import java.nio.file.Path; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Properties; import java.util.Set; import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import com.sun.javatest.TestFinder; import com.sun.javatest.TestResult; import com.sun.javatest.TestResultTable; import com.sun.javatest.TestResultTable.TreeIterator; import com.sun.javatest.TestSuite; import com.sun.javatest.WorkDirectory; import com.sun.javatest.regtest.Main.Fault; import com.sun.javatest.regtest.tool.Version; import com.sun.javatest.regtest.util.FileUtils; import com.sun.javatest.util.I18NResourceBundle; /** * Manage tests to be run by jtreg. */ public class TestManager { public static class NoTests extends Fault { private static final long serialVersionUID = 1L; public NoTests() { super(i18n, "tm.noTests"); } } private final TestFinder.ErrorHandler errHandler; private final PrintWriter out; private final Path baseDir; private Path reportDir; private Path workDir; boolean allowEmptyGroups = true; Map map = new TreeMap<>(); /** * A GroupSpec embodies an argument of the form [path]:name where path is * a file path to the root of a test suite and name is the name of a group * of tests defined in the files given in the "groups" entry in TEST.ROOT. */ public static class GroupSpec { /** The test suite containing the group, or null for the default test suite. */ final Path dir; /** The name for the group. */ final String groupName; /* A "group" argument is of the form [path]:id where the path is a file path * to the root of the test suite. On Windows, we have to be careful about * the ambiguity between an absolute path beginning with a drive letter * and a relative path that is a single letter. Therefore, on Windows, * we accept the following for a path: * - (empty) * - a single non-alphabetic character followed by :id * - two or more characters followed by :id * Thus, letter:id is not accepted as a group spec, and so will be treated * elsewhere as a plain absolute file path instead. */ static final Pattern groupPtn = System.getProperty("os.name").matches("(?i)windows.*") ? Pattern.compile("(?|[^A-Za-z]|.{2,}):(?[A-Za-z0-9_,]+)") : Pattern.compile("(?.*):(?[A-Za-z0-9_,]+)"); /** * Returns true if a string may represent a named group of tests. * * @param s the string * @return true if the string may represent a named group of tests, and false otherwise */ public static boolean isGroupSpec(String s) { return groupPtn.matcher(s).matches(); } /** * Returns an object indicating a named group of tests in a specific test suite. * * @param s a string identifying the named group of tests * @return an object indicating a named group of tests in a specific test suite */ public static GroupSpec of(String s) { Matcher m = groupPtn.matcher(s); if (!m.matches()) { throw new IllegalArgumentException(s); } String d = m.group("dir"); Path dir = d.isEmpty() ? null : Path.of(d); String groupName = m.group("group"); return new GroupSpec(dir, groupName); } private GroupSpec(Path dir, String groupName) { this.dir = dir; this.groupName = Objects.requireNonNull(groupName); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; GroupSpec groupSpec = (GroupSpec) o; return Objects.equals(dir, groupSpec.dir) && groupName.equals(groupSpec.groupName); } @Override public int hashCode() { return Objects.hash(dir, groupName); } @Override public String toString() { return (dir == null ? "" : dir) + ":" + groupName; } } /** * A TestSpec embodies an argument of the form path[#id][?query] where * path is the path for a file in a test suite, id may indicate the name * of a test within that file, and query may indicate the part of that * test to be executed. * * Note the pattern is similar to but intentionally different from that * of a URL, where the query component precedes the fragment component. * As given, path, id and query are hierarchically related. * * The path may be a directory to indicate all the tests in the files * in and under that directory. */ public static class TestSpec { public final Path file; public final String id; public final String query; /** * Returns true if a string may represent one or more tests. * * @param s the string * @return true if the string may represent one or more tests, and false otherwise */ public static boolean isTestSpec(String s) { return fileIdQueryPtn.matcher(s).matches(); } /** * Returns an object indicating one or more tests. * * @param s a string identifying one or more tests * @return an object indicating one or more tests in a specific test suite */ public static TestSpec of(String s) { Matcher m = fileIdQueryPtn.matcher(s); if (!m.matches()) { throw new IllegalArgumentException(s); } Path file = Path.of(m.group("file")); String id = m.group("id"); // may be null String query = m.group("query"); // may be null return new TestSpec(file, id, query); } static Pattern fileIdQueryPtn = Pattern.compile("(?.+?)(#(?[A-Za-z0-9-_]+))?(\\?(?.*))?"); private TestSpec(Path file, String id, String query) { this.file = Objects.requireNonNull(file); this.id = id; this.query = query; } /** * Returns the path for a test, as required by JavaTest. * The form contains the file and id as a relative URL. * It does not include the query. * * @return the path for a test */ String getTestPath() { return id == null ? pathToString(file) : pathToString(file) + "#" + id; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; TestSpec testSpec = (TestSpec) o; return file.equals(testSpec.file) && Objects.equals(id, testSpec.id) && Objects.equals(query, testSpec.query); } @Override public int hashCode() { return Objects.hash(file, id, query); } @Override public String toString() { return file + (id == null ? "" : "#" + id) + (query == null ? "" : "?" + query); } } /** * An object to encapsulate the details for the tests to be run in a single test suite. */ private static class Entry { /** * The root directory for the test specs and group specs in this entry. */ final Path rootDir; /** * Whether all tests in the test suite are to be included. * When true, the test specs and group specs are ignored. */ boolean all = false; /** * The test specs for the tests to be run. * In these specs, the file is relative to the rootDir. */ final Set tests = new LinkedHashSet<>(); /** * The names of the groups to be run. */ final Set groups = new LinkedHashSet<>(); /** * The test suite containing the test specs and group specs for this entry. */ RegressionTestSuite testSuite; /** * The subdirectory to use for the work directory and report directory, * when tests are to be run from multiple test suites. */ String subdir; /** * The work directory to use when running the tests in this entry. */ WorkDirectory workDir; /** * The report directory to use when running the tests in this entry. */ Path reportDir; Entry(Path rootDir) { this.rootDir = rootDir; } } public TestManager(PrintWriter out, Path baseDir, TestFinder.ErrorHandler errHandler) { this.out = out; this.baseDir = baseDir.toAbsolutePath(); this.errHandler = errHandler; } public void addTestSpecs(Collection tests) throws Fault { Map rootDirCache = new HashMap<>(); for (TestSpec t : tests) { Path f = canon(t.file); if (!Files.exists(f)) throw new Fault(i18n, "tm.cantFindFile", t.file); Path rootDir = getRootDir(rootDirCache, f); if (rootDir == null) throw new Fault(i18n, "tm.cantDetermineTestSuite", t.file); Entry e = getEntry(rootDir); if (f.equals(rootDir)) { e.all = true; e.tests.clear(); } else if (!e.all) { e.tests.add(new TestSpec(rootDir.relativize(f), t.id, t.query)); } } } public void addGroupSpecs(Collection groups) throws Fault { for (GroupSpec g: groups) { Path rootDir = canon((g.dir == null) ? baseDir : g.dir); if (!Files.exists(rootDir.resolve("TEST.ROOT"))) throw new Fault(i18n, "tm.badGroupTestSuite", g); Entry e = getEntry(rootDir); e.groups.add(g.groupName); } } /** * Returns whether the test manager is empty or not. * * @return true if the test manager does not contain any tests specs or group specs. */ public boolean isEmpty() { return map.isEmpty(); } /** * Returns whether the test manager contains test specs or group specs * from different test suites. * * @return true if the test manager contains test specs or group specs * from different test suites */ public boolean isMultiRun() { return (map.size() > 1); } /** * Returns the set of test suites that contain the test specs or group specs * that have been added. * * @return the test suites * @throws Fault if there is an error accessing any of the test suites */ public Set getTestSuites() throws Fault { LinkedHashSet set = new LinkedHashSet<>(); for (Entry e: map.values()) { if (e.testSuite == null) { try { e.testSuite = RegressionTestSuite.open(e.rootDir.toFile(), errHandler); if (!e.testSuite.getRootDir().toPath().equals(e.rootDir)) { System.err.println("e.testSuite.getRootDir(): " + e.testSuite.getRootDir()); System.err.println("e.rootDir: " + e.rootDir); System.err.println(e.testSuite.getRootDir().toPath().equals(e.rootDir)); throw new AssertionError(); } } catch (TestSuite.Fault f) { throw new Fault(i18n, "tm.cantOpenTestSuite", e.testSuite, f); } } set.add(e.testSuite); } return set; } /** * Sets the path for the work directory to be used for this run. * When running tests in multiple test suites, separate work * directories for each test suite will be created as subdirectories * of this directory. * * @param wd the path for the work directory */ public void setWorkDirectory(Path wd) { if (wd == null) throw new NullPointerException(); if (workDir != null) throw new IllegalStateException(); workDir = wd; } /** * Returns the path for the work directory to be used for this run. * * @return the path for the work directory */ public Path getWorkDirectory() { if (workDir == null) throw new IllegalStateException(); return workDir; } /** * Returns the work directory to be used when running tests in a given test suite. * * @param ts the test suite * @return the work directory * @throws Fault if there is a problem accessing the work directory */ public WorkDirectory getWorkDirectory(RegressionTestSuite ts) throws Fault { Entry e = map.get(ts.getRootDir().toPath()); if (e == null) throw new IllegalStateException(); if (e.workDir == null) { if (e.subdir == null && isMultiRun()) initSubdirs(); Path wd = (e.subdir == null) ? workDir : workDir.resolve(e.subdir); File wdf = wd.toFile(); try { if (WorkDirectory.isWorkDirectory(wdf)) e.workDir = WorkDirectory.open(wdf, ts); else if (Files.exists(wd)) e.workDir = WorkDirectory.convert(wdf, ts); else e.workDir = WorkDirectory.create(wdf, ts); } catch (WorkDirectory.Fault | FileNotFoundException ex) { throw new Fault(i18n, "tm.cantRead", wd.getFileName().toString(), ex); } } return e.workDir; } /** * Sets the path for the report directory to be used for this run. * When running tests in multiple test suites, separate report * directories for each test suite will be created as subdirectories * of this directory. * * @param rd the path */ public void setReportDirectory(Path rd) { if (rd == null) throw new NullPointerException(); if (reportDir != null) throw new IllegalStateException(); reportDir = rd; } /** * Returns the path for the report directory to be used for this run. * * @return the path */ public Path getReportDirectory() { if (reportDir == null) throw new IllegalStateException(); return reportDir; } /** * Returns the report directory to be used when running tests in a given test suite. * * @param ts the test suite * @return the report directory * @throws Fault if there is a problem accessing the report directory */ public Path getReportDirectory(RegressionTestSuite ts) throws Fault { Entry e = map.get(ts.getRootDir().toPath()); if (e == null) throw new IllegalArgumentException(); if (reportDir != null && e.reportDir == null) { if (e.subdir == null && isMultiRun()) initSubdirs(); e.reportDir = (e.subdir == null) ? reportDir : reportDir.resolve(e.subdir); } return e.reportDir; } /** * Returns the name of the subdirectory to use when running tests from * multiple test suites. * * @param ts the test suite * @return the name of the subdirectory * @throws Fault if there is a problem accessing the test suite */ String getSubdirectory(RegressionTestSuite ts) throws Fault { if (map.size() <= 1) return null; Entry e = map.get(ts.getRootDir().toPath()); if (e == null) throw new IllegalArgumentException(); if (e.subdir == null) initSubdirs(); return e.subdir; } /** * Returns the set of tests to be run in a given test suite, * or {@code null} meaning "all tests". * The tests are identified in "URL form", containing the * path of the test relative to the test suite root, and * with an id if given. The query part of a test spec is * not included. * * @param ts the test suite * @return the list of tests, or {@code null} for all tests * @throws Fault if there is a problem with the tests to be run */ public Set getTests(RegressionTestSuite ts) throws Fault { Entry e = map.get(ts.getRootDir().toPath()); if (e == null) { throw new IllegalArgumentException(); } if (e.all) { return null; // all tests } WorkDirectory wd = getWorkDirectory(ts); Set tests = new LinkedHashSet<>(); for (TestSpec test: e.tests) { String t = test.getTestPath(); if (validatePath(wd, t)) { tests.add(t); } else { throw new Fault(i18n, "tm.notATest", test); } } for (Path f: expandGroups(e)) { String test = pathToString(e.rootDir.relativize(f)); if (test.isEmpty()) { return null; // all tests } else if (validatePath(wd, test)) { tests.add(test); } } if (tests.isEmpty() && (!allowEmptyGroups || e.groups.isEmpty())) throw new NoTests(); return tests; } /** * Returns the list of tests to be run in a given test suite that * contain a non-null query in the test spec. * If there are multiple test specs for the same test path, then * the last one wins. This applies regardless of whether the test spec * contains a query or not. * The tests are identified in "modified URL form", containing the * path of the test relative to the test suite root, an id if given, * and the query part of the test spec. * * @param ts the test suite * @return the list of tests * @throws Fault if there is a problem with the tests to be run */ public List getTestQueries(RegressionTestSuite ts) throws Fault { Entry e = map.get(ts.getRootDir().toPath()); if (e == null) { throw new IllegalArgumentException(); } if (e.all) { return List.of(); } // Eliminate any duplicates for each test path with "last one wins" Map map = new LinkedHashMap<>(); for (TestSpec t : e.tests) { if (t.query != null && Files.isDirectory(e.rootDir.resolve(t.file))) { throw new Fault(i18n, "tm.invalidQuery", t); } map.put(t.getTestPath(), t); } // Return the remaining test specs that contain a query component return map.values().stream() .filter(t -> t.query != null) .map(t -> t.getTestPath() + "?" + t.query) .collect(Collectors.toList()); } // This method is to work around a bug in TestResultTable.validatePath // such that the extension of the file name is not validated. // In other words, an invalid path dir/file.ex1 will be reported as // valid if dir/file.ex2 exists and is valid. // The problem only exists for paths to files (not directories.) // The solution is to check the root-relative path in the test description // to make sure it is the same as the original path. // See JBS CODETOOLS-7900138, CODETOOLS-7900139 private boolean validatePath(WorkDirectory wd, String path) { try { TestResultTable trt = wd.getTestResultTable(); if (trt.validatePath(path)) { // bypass check when fragment syntax used if (path.matches(".*#[A-Za-z0-9-_]+")) return true; File rootDir = wd.getTestSuite().getRootDir(); File f = new File(rootDir, path); if (f.isDirectory()) return true; TreeIterator iter = trt.getIterator(new String[] { path }); while (iter.hasNext()) { TestResult tr = iter.next(); String trp = tr.getDescription().getRootRelativePath(); if (path.equals(trp)) return true; } } return false; } catch (TestResult.Fault f) { return false; } } /** * Returns the names of the groups containing tests to be run in * the given test suite. * * @param ts the test suite * @return the names of the groups to be run * @throws Fault if there is a problem accessing the groups */ public Set getGroups(RegressionTestSuite ts) throws Fault { Entry e = map.get(ts.getRootDir().toPath()); if (e == null) throw new IllegalArgumentException(); return e.groups; } private Entry getEntry(Path rootDir) { Entry e = map.get(rootDir); if (e == null) map.put(rootDir, e = new Entry(rootDir)); return e; } /** * Get the test suite root for a file in a test suite * @param rootDirCache a cache of earlier results to improve performance * @param file the file to test * @return the path for the enclosing directory containing TEST.ROOT, * or null if there is no such directory */ private Path getRootDir(Map rootDirCache, Path file) { if (file == null) return null; if (Files.isRegularFile(file)) return getRootDir(rootDirCache, file.getParent()); Path ts = rootDirCache.get(file); if (ts == null) { ts = Files.exists(file.resolve("TEST.ROOT")) ? file : getRootDir(rootDirCache, file.getParent()); rootDirCache.put(file, ts); } return ts; } /** * Determine subdirectories to use within a top-level work directory. * Existing subdirectories are honored if applicable. */ private void initSubdirs() throws Fault { if (WorkDirectory.isWorkDirectory(workDir.toFile())) throw new Fault(i18n, "tm.workDirNotSuitableInMultiTestSuiteMode"); Set subdirs = new HashSet<>(); // first, scan directory looking for existing test suites if (Files.exists(workDir)) { if (!Files.isDirectory(workDir)) throw new Fault(i18n, "tm.notADirectory", workDir); for (Path f: FileUtils.listFiles(workDir)) { String subdir = f.getFileName().toString(); subdirs.add(subdir); // record all names to avoid downstream clashes if (WorkDirectory.isUsableWorkDirectory(f.toFile())) { File tsr = getTestSuiteForWorkDirectory(f.toFile()); Entry e = map.get(tsr.toPath()); if (e != null) e.subdir = subdir; } } } // create new entries for test suites that do not have them for (Entry e: map.values()) { if (e.subdir == null) { String subdir = e.rootDir.getFileName().toString(); if (e.rootDir.getParent() != null) subdir = e.rootDir.getParent().getFileName() + "_" + subdir; if (subdirs.contains(subdir)) { int n = 0; String sdn; while (subdirs.contains(sdn = (subdir + "_" + n))) n++; subdir = sdn; } e.subdir = subdir; subdirs.add(subdir); } } } private File getTestSuiteForWorkDirectory(File wd) { // Cannot use standard WorkDirectory.open(ws).getTestSuite().getRoot() // because jtreg does not follow standard protocol for tsInfo. // (There is no easy way to disambiguate jtreg test suites.) // So, have to read the testsuite file directly. File tsInfo = new File(new File(wd, "jtData"), "testsuite"); try { try (InputStream in = new FileInputStream(tsInfo)) { Properties p = new Properties(); p.load(in); String tsr = p.getProperty("root"); if (tsr != null) return new File(tsr); } } catch (IOException e) { // ignore } return new File("__UNKNOWN__"); } private Set expandGroups(Entry e) throws Fault { try { Set results = new LinkedHashSet<>(); GroupManager gm = e.testSuite.getGroupManager(out); if (gm.invalid()) { Version v = e.testSuite.getRequiredVersion(); boolean reportErrorIfInvalidGroups = (v.version != null) && (v.compareTo(new Version("5.1 b01")) >= 0); if (reportErrorIfInvalidGroups) { throw new Fault(i18n, "tm.invalidGroups"); } } for (String group: e.groups) { try { results.addAll(gm.getFiles(group)); } catch (GroupManager.InvalidGroup ex) { throw new Fault(i18n, "tm.invalidGroup", group); } } return results; } catch (IOException ex) { throw new Fault(i18n, "tm.cantReadGroups", e.testSuite.getRootDir(), ex); } } private Path canon(Path file) { Path f = file.isAbsolute() ? file : baseDir.resolve(file); try { return f.toRealPath(); } catch (IOException e) { return getNormalizedFile(f); } } private static Path getNormalizedFile(Path f) { return f.toAbsolutePath().normalize(); } private static String pathToString(Path p) { return p.toString().replace(File.separatorChar, '/'); } private static final I18NResourceBundle i18n = I18NResourceBundle.getBundleForClass(TestManager.class); } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/config/TestProperties.java000066400000000000000000000513251461415321300312670ustar00rootroot00000000000000/* * Copyright (c) 1997, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.config; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.lang.ref.SoftReference; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import com.sun.javatest.TestFinder; import com.sun.javatest.TestSuite; import com.sun.javatest.regtest.tool.Version; import com.sun.javatest.regtest.util.StringUtils; import com.sun.javatest.util.I18NResourceBundle; /** * Provide access to properties defined in TEST.ROOT, with selective overrides * in TEST.properties in subdirectories. */ public class TestProperties { TestProperties(File rootDir, TestFinder.ErrorHandler errHandler) { this.errHandler = errHandler; cache = new Cache(canon(rootDir)); Cache.Entry e = cache.getEntry(cache.rootDir); validKeys = e.validKeys; // determine whether we want to enforce bugid syntax // the default is that we always do String bug = e.properties.getProperty("checkBugID"); checkBugID = (bug == null) || !bug.trim().equals("false"); String mode = e.properties.getProperty("defaultExecMode"); defaultExecMode = ExecMode.fromString(mode); String gf = e.properties.getProperty("groups"); groupFiles = (gf == null) ? Collections.emptyList() : List.of(gf.split("\\s+")); String version = e.properties.getProperty("requiredVersion"); requiredVersion = new Version(version); String epd = e.properties.getProperty("requires.extraPropDefns"); if (epd == null) { extraPropDefns = new ExtraPropDefns(); } else { extraPropDefns = new ExtraPropDefns( epd, e.properties.getProperty("requires.extraPropDefns.libs"), e.properties.getProperty("requires.extraPropDefns.bootlibs"), e.properties.getProperty("requires.extraPropDefns.javacOpts"), e.properties.getProperty("requires.extraPropDefns.vmOpts") ); } } Set getValidKeys(File file) throws TestSuite.Fault { if (!allowLocalKeys) return validKeys; return getEntry(file).validKeys; } Set getValidRequiresProperties(File file) throws TestSuite.Fault { return getEntry(file).validRequiresProperties; } ExecMode getDefaultExecMode() { return defaultExecMode; } List getGroupFiles() { return groupFiles; } boolean useBootClassPath(File file) throws TestSuite.Fault { return getEntry(file).useBootClassPath; } boolean useOtherVM(File file) throws TestSuite.Fault { return getEntry(file).useOtherVM; } boolean isTestNG(File file) throws TestSuite.Fault { return getEntry(file).testNGRoot != null; } File getTestNGRoot(File file) throws TestSuite.Fault { return getEntry(file).testNGRoot; } boolean isJUnit(File file) throws TestSuite.Fault { return getEntry(file).junitRoot != null; } File getJUnitRoot(File file) throws TestSuite.Fault { return getEntry(file).junitRoot; } boolean needsExclusiveAccess(File file) throws TestSuite.Fault { return getEntry(file).needsExclusiveAccess; } Set getLibDirs(File file) throws TestSuite.Fault { return getEntry(file).libDirs; } Set getLibBuildArgs(File file) throws TestSuite.Fault { return getEntry(file).libBuildArgs; } Set getModules(File file) throws TestSuite.Fault { return getEntry(file).modules; } Version getRequiredVersion() { return requiredVersion; } Set getExternalLibs(File file) throws TestSuite.Fault { return getEntry(file).extLibRoots; } ExtraPropDefns getExtraPropDefns() { return extraPropDefns; } int getMaxOutputSize(File file) { return getEntry(file).maxOutputSize; } boolean getAllowSmartActionArgs(File file) { return getEntry(file).allowSmartActionArgs; } boolean getEnablePreview(File file) { return getEntry(file).enablePreview; } private Cache.Entry getEntry(File file) { File dir = file.isDirectory() ? file : file.getParentFile(); return cache.getEntry(dir); } private void error(I18NResourceBundle i18n, String key, Object... args) { errHandler.error(i18n.getString(key, args)); } private File canon(File f) { try { return f.getCanonicalFile(); } catch (IOException e) { return new File(f.getAbsoluteFile().toURI().normalize()); } } private final TestFinder.ErrorHandler errHandler; private final Cache cache; /*private*/ final boolean checkBugID; /*private*/ final Set validKeys; final ExecMode defaultExecMode; final List groupFiles; final Version requiredVersion; final ExtraPropDefns extraPropDefns; class Cache { class Entry { final Entry parent; final File dir; final Properties properties; final Set validKeys; final Set validRequiresProperties; final boolean useBootClassPath; private final Set bootClassPathDirs; final boolean useOtherVM; private final Set otherVMDirs; final boolean needsExclusiveAccess; private final Set exclusiveAccessDirs; final File testNGRoot; private final Set testNGDirs; final File junitRoot; private final Set junitDirs; final Set libDirs; final Set libBuildArgs; final Set extLibRoots; final Set modules; final int maxOutputSize; final boolean allowSmartActionArgs; final boolean enablePreview; Entry(Entry parent, File dir) { this.parent = parent; this.dir = dir; File file = new File(dir, (parent == null) ? "TEST.ROOT" : "TEST.properties"); if (file.canRead()) { properties = (parent == null) ? new Properties() : new Properties(parent.properties); try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(file))) { properties.load(in); } catch (IOException e) { error(i18n, "props.cantRead", file); } // add the list of valid keys validKeys = initKeywordSet(parent == null ? null : parent.validKeys, "keys"); // add the list of valid properties for @requires validRequiresProperties = initSimpleSet(parent == null ? null : parent.validRequiresProperties, "requires.properties"); // add the list of bootclasspath dirs bootClassPathDirs = initFileSet(parent == null ? null : parent.bootClassPathDirs, "bootclasspath.dirs", dir); // add the list of othervm dirs otherVMDirs = initFileSet(parent == null ? null : parent.otherVMDirs, "othervm.dirs", dir); // add the list of exclusive access dirs exclusiveAccessDirs = initFileSet(parent == null ? null : parent.exclusiveAccessDirs, "exclusiveAccess.dirs", dir); // add the list of TestNG dirs testNGDirs = initFileSet(parent == null ? null : parent.testNGDirs, "TestNG.dirs", dir); // add the list of JUnit dirs junitDirs = initFileSet(parent == null ? null : parent.junitDirs, "JUnit.dirs", dir); // add the list of library dirs for TestNG tests libDirs = initLibDirSet(parent == null ? null : parent.libDirs, "lib.dirs", dir); // add the list of library dirs for TestNG tests libBuildArgs = initSimpleSet(parent == null ? null : parent.libBuildArgs, "lib.build"); // add the list of external library roots extLibRoots = initFileSet(parent == null ? null : parent.extLibRoots, "external.lib.roots", dir); // add the list of default modules used by tests modules = initSimpleSet(parent == null ? null : parent.modules, "modules"); // add the maxOutputSize for result content maxOutputSize = getInt("maxOutputSize", -1); // determine whether tests can use "smart action args" allowSmartActionArgs = initAllowSmartActionArgs(parent); // determine whether tests use preview features, and so require --enable-preview option enablePreview = initEnablePreview(parent); } else { if (parent == null) throw new IllegalStateException("TEST.ROOT not found"); properties = parent.properties; validKeys = parent.validKeys; validRequiresProperties = parent.validRequiresProperties; bootClassPathDirs = parent.bootClassPathDirs; otherVMDirs = parent.otherVMDirs; exclusiveAccessDirs = parent.exclusiveAccessDirs; testNGDirs = parent.testNGDirs; junitDirs = parent.junitDirs; libDirs = parent.libDirs; libBuildArgs = parent.libBuildArgs; extLibRoots = parent.extLibRoots; modules = parent.modules; maxOutputSize = parent.maxOutputSize; allowSmartActionArgs = parent.allowSmartActionArgs; enablePreview = parent.enablePreview; } useBootClassPath= initUseBootClassPath(parent, dir); useOtherVM = initUseOtherVM(parent, dir); needsExclusiveAccess = initNeedsExclusiveAccess(parent, dir); testNGRoot = initTestNGRoot(parent, dir); junitRoot = initJUnitRoot(parent, dir); } private int getInt(String propertyName, int defaultValue) { String v = properties.getProperty(propertyName); try { if (v != null) { return Integer.parseInt(v.trim()); } } catch (NumberFormatException e) { error(i18n, "props.bad.value", propertyName, v); } return defaultValue; } private Set initFileSet(Set parent, String propertyName, File baseDir) { String[] values = StringUtils.splitWS(properties.getProperty(propertyName)); if (parent == null || values.length > 0) { Set set = (parent == null) ? new LinkedHashSet<>() : new LinkedHashSet<>(parent); //set.addAll(List.of(values)); for (String v: values) { File f = toFile(baseDir, v); if (f != null) set.add(f); } return Collections.unmodifiableSet(set); } else { return parent; } } private Set initLibDirSet(Set parent, String propertyName, File baseDir) { String[] values = StringUtils.splitWS(properties.getProperty(propertyName)); if (parent == null || values.length > 0) { Set set = (parent == null) ? new LinkedHashSet<>() : new LinkedHashSet<>(parent); for (String v: values) { if (v.startsWith("/")) { set.add(v); } else { File f = toFile(baseDir, v); if (f != null) { set.add("/" + rootDir.toPath() .relativize(f.toPath()) .toString() .replace(File.separatorChar, '/')); } } } return Collections.unmodifiableSet(set); } else { return parent; } } private Set initKeywordSet(Set parent, String propertyName) { String[] values = StringUtils.splitWS(properties.getProperty(propertyName)); if (parent == null || values.length > 0) { Set set = (parent == null) ? new LinkedHashSet<>() : new LinkedHashSet<>(parent); for (String v: values) { try { RegressionKeywords.validateKey(v); set.add(v.replace("-", "_")); } catch (RegressionKeywords.Fault e) { File file = new File(dir, (parent == null) ? "TEST.ROOT" : "TEST.properties"); error(i18n, "props.bad.keyword", file, v, e.getMessage()); } } return Collections.unmodifiableSet(set); } else { return parent; } } private Set initSimpleSet(Set parent, String propertyName) { String[] values = StringUtils.splitWS(properties.getProperty(propertyName)); if (parent == null || values.length > 0) { Set set = (parent == null) ? new LinkedHashSet<>() : new LinkedHashSet<>(parent); set.addAll(List.of(values)); return Collections.unmodifiableSet(set); } else { return parent; } } private boolean initUseBootClassPath(Entry parent, File dir) { if (parent == null) return false; if (parent.useBootClassPath) return true; for (File bootClassPathDir: bootClassPathDirs) { if (includes(bootClassPathDir, dir)) return true; } return false; } private boolean initUseOtherVM(Entry parent, File dir) { if (parent == null) return false; if (parent.useOtherVM) return true; for (File otherVMDir: otherVMDirs) { if (includes(otherVMDir, dir)) return true; } return false; } private boolean initNeedsExclusiveAccess(Entry parent, File dir) { if (parent == null) return false; if (parent.needsExclusiveAccess) return true; for (File exclusiveAccessDir: exclusiveAccessDirs) { if (includes(exclusiveAccessDir, dir)) return true; } return false; } private File initTestNGRoot(Entry parent, File dir) { if (parent == null) return null; if (parent.testNGRoot != null) return parent.testNGRoot; for (File testNGDir: testNGDirs) { if (includes(testNGDir, dir)) return testNGDir; } return null; } private File initJUnitRoot(Entry parent, File dir) { if (parent == null) return null; if (parent.junitRoot != null) return parent.junitRoot; for (File junitDir: junitDirs) { if (includes(junitDir, dir)) return junitDir; } return null; } private boolean includes(File dir, File file) { for ( ; file != null; file = file.getParentFile()) { if (dir.equals(file)) return true; } return false; } private boolean initAllowSmartActionArgs(Entry parent) { if (properties.containsKey("allowSmartActionArgs")) { return properties.getProperty("allowSmartActionArgs").equals("true"); } if (parent != null) { return parent.allowSmartActionArgs; } // If and when this code is run, the main requiredVersion member is not yet initialized. String rv = properties.getProperty("requiredVersion"); if (rv != null) { return new Version(rv).compareTo(new Version("4.2 b14")) >= 0; } return false; } private boolean initEnablePreview(Entry parent) { if (properties.containsKey("enablePreview")) { return properties.getProperty("enablePreview").equals("true"); } if (parent != null) { return parent.enablePreview; } return false; } private File toFile(File baseDir, String v) { if (v.startsWith("/")) { File f = new File(rootDir, v.substring(1)); if (f.exists()) return new File(f.toURI().normalize()); } else { File f; if ((f = new File(baseDir, v)).exists()) return new File(f.toURI().normalize()); else if ((f = new File(rootDir, v)).exists()) // for backwards compatibility return new File(f.toURI().normalize()); } return null; } } /** Cache map, using soft references. */ Map> map; /** Strong reference to most recent entry, and all its ancestors */ Entry lastUsedEntry; File rootDir; Cache(File rootDir) { this.rootDir = rootDir; map = new HashMap<>(); } synchronized Entry getEntry(File dir) { if (lastUsedEntry == null || !lastUsedEntry.dir.equals(dir)) lastUsedEntry = getEntryInternal(dir); return lastUsedEntry; } private Entry getEntryInternal(File dir) { SoftReference ref = map.get(dir); Entry e = (ref == null) ? null : ref.get(); if (e == null) { Entry parent = dir.equals(rootDir) ? null : getEntryInternal(dir.getParentFile()); map.put(dir, new SoftReference<>(e = new Entry(parent, dir))); } return e; } } private static final boolean allowLocalKeys = Boolean.parseBoolean(System.getProperty("javatest.regtest.allowLocalKeys", "true")); private static final I18NResourceBundle i18n = I18NResourceBundle.getBundleForClass(RegressionTestSuite.class); } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/config/i18n.properties000066400000000000000000000050501461415321300303170ustar00rootroot00000000000000# # Copyright (c) 1999, 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. Oracle designates this # particular file as subject to the "Classpath" exception as provided # by Oracle in the LICENSE file that accompanied this code. # # 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. # finder.cant.read.test.properties=Problem reading TEST.properties: {0} finder.ioError=Error reading file: {0} finder.jtrClash=Test clashes with another test with a similar name:\n {0}\n {1} props.bad.keyword={0}: bad keyword ''{1}'': {2} props.bad.value={0}: bad value for ''{1}'': {2} props.cantRead=can''t read file: {0} suite.cantCreateInterview=can''t create interview: {0} gm.cycle.detected=cycle detected gm.file.group.prefix={0}: group {1}: {2} gm.file.not.found=file not found: {0} gm.group.includes.itself=group includes itself gm.group.not.found=group not found: {0} gm.group.prefix=group {0}: {2} gm.invalid.name.for.group=invalid name for group rp.badPath="Bad path: {0}: {1} tm.badGroupTestSuite=Group spec does not specify a valid test suite: {0} tm.cantDetermineTestSuite=Cannot determine test suite from test (is TEST.ROOT missing?): {0} tm.cantFindFile=Cannot find file: {0} tm.cantRead=Cannot read {0}: {1} tm.cantReadGroups=Cannot read group files for {0}: {1} tm.cantOpenTestSuite=Cannot open test suite {0}: {1} tm.invalidGroup=Group is invalid: {0} tm.invalidGroups=One or more groups are invalid tm.invalidQuery=Invalid use of query component: {0} tm.notADirectory=Not a directory: {0} tm.notATest=Not a test or directory containing tests: {0} tm.noTests=No tests selected tm.workDirNotSuitableInMultiTestSuiteMode=\ Work directory not suitable for use in multi test suite mode jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/config/package-info.java000066400000000000000000000034771461415321300306240ustar00rootroot00000000000000/* * Copyright (c) 2016, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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. */ /** * Provides support classes for the JDK Regression Test Harness, jtreg, * for configuring a test run. * *

* The primary class in this package is {@link RegressionTestSuite}, * which provides access to {@link RegressionTestFinder}, used to locate * tests in the test suite; and {@link RegressionParameters}, used to * provide the configuration details for a test run. * *

This is NOT part of any supported API. * If you write code that depends on this, you do so at your own risk. * This code and its internal interfaces are subject to change or * deletion without notice. */ package com.sun.javatest.regtest.config; jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/exec/000077500000000000000000000000001461415321300251015ustar00rootroot00000000000000jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/exec/Action.java000066400000000000000000001040561461415321300271670ustar00rootroot00000000000000/* * Copyright (c) 1998, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.exec; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.jar.Attributes; import java.util.jar.JarFile; import java.util.jar.Manifest; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.sun.javatest.Status; import com.sun.javatest.TestResult; import com.sun.javatest.regtest.agent.ActionHelper; import com.sun.javatest.regtest.agent.Flags; import com.sun.javatest.regtest.agent.SearchPath; import com.sun.javatest.regtest.config.ExecMode; import com.sun.javatest.regtest.config.Modules; import com.sun.javatest.regtest.config.OS; import com.sun.javatest.regtest.config.ParseException; import com.sun.javatest.regtest.util.FileUtils; import com.sun.javatest.regtest.util.StringUtils; /** * Action is an abstract base class providing the ability to control the * behavior of each step in a JDK test description. This class requires that * all derived classes implement the init method (where arguments are * processed and other initializations occur) and the run method (where * the actual work for the action occurs. In addition to these methods, the * Action abstract class contains a variety of protected methods for parsing and * logging. All static strings used in Action implementations are also defined * here. */ public abstract class Action extends ActionHelper { /** * The null constructor. */ public Action() { } // Action() /** * Get the user-visible name of this action. * @return the user-visible name of this action. */ public abstract String getName(); /** * This method does initial processing of the options and arguments for the * action. Processing is determined by the requirements of run() which is * determined by the tag specification. * * @param opts The options for the action. * @param args The arguments for the actions. * @param reason Indication of why this action was invoked. * @param script The script. * @exception ParseException If the options or arguments are not expected * for the action or are improperly formated. */ public void init(Map opts, List args, String reason, RegressionScript script) throws ParseException { this.opts = opts; this.args = args; this.reason = reason; this.script = script; } /** * The method that does the work of the action. The necessary work for the * given action is defined by the tag specification. * * @return The result of the action. * @exception TestRunException If an unexpected error occurs while running * the test. */ public abstract Status run() throws TestRunException; /** * Get any source files directly referenced by this action. * @return the source files used by this action. **/ public Set getSourceFiles() { return null; } /** * Get the set of modules directly referenced in this action. * @return the set of modules used by this action. */ public Set getModules() { return Collections.emptySet(); } protected Map getEnvVars(boolean nativeCode) { Map envVars = script.getEnvVars(); if (nativeCode) { Path nativeDir = script.getNativeDir(); if (nativeDir != null) { envVars = new LinkedHashMap<>(envVars); String libPathName; OS os = OS.current(); switch (os.family) { case "aix": case "os400": libPathName = "LIBPATH"; break; case "mac": libPathName = "DYLD_LIBRARY_PATH"; break; case "windows": libPathName = "PATH"; break; default: libPathName = "LD_LIBRARY_PATH"; break; } String libPath = envVars.get(libPathName); if (libPath == null) { envVars.put(libPathName, nativeDir.toString()); } else { envVars.put(libPathName, libPath + File.pathSeparator + nativeDir); } envVars = Collections.unmodifiableMap(envVars); } } return envVars; } static synchronized void mkdirs(File dir) { dir.mkdirs(); } public File getArgFile() { Path f = script.absTestWorkFile(getName() + "." + script.getNextSerial() + ".jta"); FileUtils.createDirectories(f.getParent()); return f.toFile(); } //------------------- parsing ----------------------------------------------- /** * This method parses the timeout action option used by several * actions. It verifies that the value of the timeout is a valid number. * * @param value The proposed value of the timeout. * @return An integer representation of the passed value for the * timeout scaled by the timeout factor. * @exception ParseException If the string does not have a valid * interpretation as a number. */ protected int parseTimeout(String value) throws ParseException { if (value == null) throw new ParseException(PARSE_TIMEOUT_NONE); try { return script.getActionTimeout(Integer.parseInt(value)); } catch (NumberFormatException e) { throw new ParseException(PARSE_TIMEOUT_BAD_INT + value); } } // parseTimeout() /** * This method parses the fail action option used by several * actions. It verifies that there is no associated value for the option. * * @param value The proposed value of the fail. * @return True if there is no associated value. * @exception ParseException If there is an associated value. */ protected boolean parseFail(String value) throws ParseException { if (value != null) throw new ParseException(PARSE_FAIL_UEXPECT + value); return true; } // parseFail() /** * This method parses the module action option used by some * actions. * * @param value The proposed value of the module * @return True if the value is a legal identifier. * @exception ParseException If there is an associated value. */ protected String parseModule(String value) throws ParseException { if (value == null) throw new ParseException(PARSE_MODULE_NONE); if (!isQualifiedName(value)) throw new ParseException(PARSE_MODULE_INVALID + value); return value; } private boolean isQualifiedName(String name) { boolean beginIdent = true; for (int i = 0; i < name.length(); i++) { char ch = name.charAt(i); if (beginIdent) { if (!Character.isJavaIdentifierStart(ch)) { return false; } beginIdent = false; } else { if (ch == '.') { beginIdent = true; } else if (!Character.isJavaIdentifierPart(ch)) { return false; } } } return !beginIdent; } //-------------------------------------------------------------------------- /** * Add a grant entry to the policy file so that jtreg and other libraries can read * JTwork/classes. * The remaining entries in the policy file should remain the same. * * @param fileName The absolute name of the original policy file. * @return A string indicating the absolute name of the modified policy * file. * @throws TestRunException if a problem occurred adding this grant entry. */ protected File addGrantEntries(File fileName) throws TestRunException { return addGrantEntries(fileName, null); } /** * Add a grant entry to the policy file so that jtreg and other libraries can read * JTwork/classes. An entry is added for the argFile, if one is given. * * The remaining entries in the policy file should remain the same. * * @param fileName the absolute name of the original policy file * @param argFile an additional file to be granted permissions * @return a string indicating the absolute name of the modified policy file * @throws TestRunException if a problem occurred adding this grant entry. */ protected File addGrantEntries(File fileName, File argFile) throws TestRunException { File newPolicy = script.absTestScratchDir().resolve(fileName.getName() + "_new").toFile(); try { try (FileWriter fw = new FileWriter(newPolicy)) { fw.write("// The following grant entries were added by jtreg. Do not edit." + LINESEP); fw.write("grant {" + LINESEP); fw.write(" permission java.io.FilePermission \"" + script.absTestClsTopDir().toString().replace(FILESEP, "{/}") + "${/}-\", \"read\";" + LINESEP); if (argFile != null) { fw.write(" permission java.io.FilePermission \"" + argFile.getPath().replace(FILESEP, "{/}") + "\", \"read\";" + LINESEP); } fw.write("};" + LINESEP); List libs = new ArrayList<>(); libs.addAll(script.getJavaTestClassPath().asList()); if (script.isJUnitRequired()) { libs.addAll(script.getJUnitPath().asList()); } if (script.isTestNGRequired()) { libs.addAll(script.getTestNGPath().asList()); } for (Path lib : libs) { fw.write("grant codebase \"" + lib.toUri() + "\" {" + LINESEP); fw.write(" permission java.security.AllPermission;" + LINESEP); fw.write("};" + LINESEP); } fw.write(LINESEP); fw.write("// original policy file:" + LINESEP); fw.write("// " + fileName + LINESEP); try (BufferedReader in = new BufferedReader(new FileReader(fileName))) { String line; while ((line = in.readLine()) != null) { fw.write(line + LINESEP); } } } } catch (IOException e) { throw new TestRunException(POLICY_WRITE_PROB + newPolicy); } catch (SecurityException e) { throw new TestRunException(POLICY_SM_PROB + newPolicy); } return newPolicy; } // addGrantEntries() /** * This method parses the policy action option used by several * actions. It verifies that the indicated policy file exists in the * directory containing the defining file of the test. * * @param value The proposed filename for the policy file. * @return a file representing the absolute name of the policy file for * the test. * @exception ParseException If the passed filename is null, the empty * string, or does not exist. */ protected File parsePolicy(String value) throws ParseException { if ((value == null) || value.equals("")) throw new ParseException(MAIN_NO_POLICY_NAME); File policyFile = script.absTestSrcDir().resolve(value).toFile(); if (!policyFile.exists()) throw new ParseException(MAIN_CANT_FIND_POLICY + policyFile); return policyFile; } // parsePolicy() /** * This method parses the secure action option used to provide the * name of a subclass to be installed as the security manager. No * verification of the existence of the .class is done. * * @param value The proposed class name for the security manager. * @return A string indicating the absolute name of the security manager * class. * @exception ParseException If the passed classname is null, the empty * string */ protected String parseSecure(String value) throws ParseException { if ((value == null) || value.equals("")) throw new ParseException(MAIN_NO_SECURE_NAME); return value; } // parseSecure() //----------logging methods------------------------------------------------- /** * Set up a recording area for the action. The initial contents of the * default message area are set and will be of the form: *

     * command: action [command_args]
     * reason: [reason_string]
     * 
* @param initConfig whether or not to initialize a configuration section */ protected void startAction(boolean initConfig) { String name = getName(); section = script.getTestResult().createSection(name); PrintWriter pw = section.getMessageWriter(); pw.println(LOG_COMMAND + name + " " + StringUtils.join(args, " ")); pw.println(LOG_REASON + reason); recorder = new ActionRecorder(this); if (initConfig) { configWriter = section.createOutput("configuration"); } Date startDate = new Date(); startTime = startDate.getTime(); pw.println(LOG_STARTED + startDate); } // startAction() /** * Set the status for the passed action. After this call, the recording area * for the action become immutable. * * @param status The final status of the action. */ protected void endAction(Status status) { Date endDate = new Date(); long elapsedTime = endDate.getTime() - startTime; PrintWriter pw = section.getMessageWriter(); pw.println(LOG_FINISHED + endDate); pw.println(LOG_ELAPSED_TIME + ((double) elapsedTime/1000.0)); recorder.close(); section.setStatus(status); } // endAction() //----------workarounds------------------------------------------------------- /** * This method pushes the full, constructed command for the action to the * log. The constructed command contains the action and its arguments * modified to run in another process. The command may also contain * additional things necessary to run the action according to spec. This * may include things such as a modified classpath, absolute names of files, * and environment variables. * * Used primarily for debugging purposes. * * @param action The name of the action currently being processed. * @param cmdArgs An array of the command to pass to ProcessCommand. * @param section The section of the result file for this action. * @see com.sun.javatest.lib.ProcessCommand#run */ protected void showCmd(String action, String[] cmdArgs, TestResult.Section section) { showCmd(action, List.of(cmdArgs), section); } protected void showCmd(String action, List cmdArgs, TestResult.Section section) { PrintWriter pw = section.getMessageWriter(); pw.println(LOG_JT_COMMAND + action); for (String s: cmdArgs) pw.print("'" + s + "' "); pw.println(); } // showCmd() // this has largely been superseded by the default show mode code protected void showMode(String action, ExecMode mode, TestResult.Section section) { PrintWriter pw = section.getMessageWriter(); pw.println("MODE: " + mode); } protected void showMode(ExecMode mode) { showMode(mode, null); } protected void showMode(ExecMode mode, Set reasons) { PrintWriter pw = section.getMessageWriter(); pw.print("Mode: " + mode.name().toLowerCase()); if (reasons != null && !reasons.isEmpty()) { pw.print(" "); pw.print(reasons); } pw.println(); } /** * Given a string, change "\\" into "\\\\" for windows platforms. This method * must be called exactly once before the string is used to start a new * process. * * @param s The string to translate. * @return For Windows systems, a modified string. For all other * systems including i386 (win32 sparc and Linux), the same * string. */ String[] quoteBackslash(String[] s) { String bs = "\\"; String[] retVal = new String[s.length]; if (System.getProperty("file.separator").equals(bs)) { for (int i = 0; i < s.length; i++) { String victim = s[i]; StringBuilder sb = new StringBuilder(); for (int j = 0; j < victim.length(); j++) { String c = String.valueOf(victim.charAt(j)); sb.append(c); if (c.equals(bs)) sb.append(c); } retVal[i] = sb.toString(); } } else retVal = s; return retVal; } // quoteBackslash() /** * Single quote the given string. This method should be used if the string * contains characters which should not be interpreted by the shell. * * @param s The string to translate. * @return The same string, surrounded by "'". */ String singleQuoteString(String s) { StringBuilder b = new StringBuilder(); b.append("'").append(s).append("'"); return(b.toString()); } // singleQuoteString() //-------------------------------------------------------------------------- protected static List join(List l1, List l2) { List result = new ArrayList<>(); result.addAll(l1); result.addAll(l2); return result; } //-------------------------------------------------------------------------- Set getModules(SearchPath pp) { if (pp == null) return Collections.emptySet(); Set results = new LinkedHashSet<>(); for (Path element : pp.asList()) { if (Files.isRegularFile(element)) { getModule(element, results); } else if (Files.isDirectory(element)) { for (Path file : FileUtils.listFiles(element)) { getModule(file, results); } } } return results; } private void getModule(Path file, Set results) { if (isModule(file)) { results.add(file.getFileName().toString()); } else if (file.getFileName().toString().endsWith(".jar")) { results.add(getAutomaticModuleName(file)); } } private boolean isModule(Path f) { if (Files.isDirectory(f)) { if (script.systemModules.contains(f.getFileName().toString())) { return true; } if (Files.exists(f.resolve("module-info.class"))) return true; if (Files.exists(f.resolve("module-info.java"))) return true; } return false; } private static final Map automaticNames = new ConcurrentHashMap<>(); // see java.lang.module.ModulePath.deriveModuleDescriptor // See ModuleFinder.of for info on determining automatic module names // https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/module/ModuleFinder.html#of(java.nio.file.Path...) private String getAutomaticModuleName(Path f) { // Step 0: see if already cached String cached = automaticNames.get(f); if (cached != null) { return cached; } // Step 1: check for Automatic-Module-Name in thge main jar file manifest try (JarFile jar = new JarFile(f.toFile())) { Manifest mf = jar.getManifest(); Attributes attrs = mf.getMainAttributes(); String amn = attrs.getValue("Automatic-Module-Name"); if (amn != null) { automaticNames.put(f, amn); return amn; } } catch (IOException e) { script.getMessageWriter().println("Problem reading jar manifest to get Automatic-Module-Name: " + f + " " + e); } // Step 2: infer the name from the jar file name String fn = f.getFileName().toString(); // drop .jar String mn = fn.substring(0, fn.length()-4); String vs = null; // find first occurrence of -${NUMBER}. or -${NUMBER}$ Matcher matcher = Pattern.compile("-(\\d+(\\.|$))").matcher(mn); if (matcher.find()) { int start = matcher.start(); // drop tail (ignore version info) mn = mn.substring(0, start); } // finally clean up the module name mn = mn.replaceAll("[^A-Za-z0-9]", ".") // replace non-alphanumeric .replaceAll("(\\.)(\\1)+", ".") // collapse repeating dots .replaceAll("^\\.", "") // drop leading dots .replaceAll("\\.$", ""); // drop trailing dots return mn; } //----------module exports---------------------------------------------------- protected List getExtraModuleConfigOptions(Modules.Phase phase) { if (!script.getTestJDK().hasModules()) return Collections.emptyList(); Modules modules = script.getModules(); boolean needAddExports = false; Set addModules = null; for (Modules.Entry e: modules) { String m = e.moduleName; if (e.needAddExports()) { needAddExports = true; } if (addModules == null) { addModules = new LinkedHashSet<>(); } addModules.add(m); } if (!needAddExports && addModules == null) { return Collections.emptyList(); } List list = new ArrayList<>(); if (addModules != null) { list.add("--add-modules"); list.add(StringUtils.join(addModules, ",")); } for (Modules.Entry e: modules) { if (e.packageName != null) { if (e.addExports) { list.add("--add-exports"); list.add(e.moduleName + "/" + e.packageName + "=ALL-UNNAMED"); } if (e.addOpens && (phase == Modules.Phase.DYNAMIC)) { list.add("--add-opens"); list.add(e.moduleName + "/" + e.packageName + "=ALL-UNNAMED"); } } } PrintWriter pw = section.getMessageWriter(); pw.println("Additional options from @modules: " + StringUtils.join(list, " ")); return list; } protected boolean includesOption(String option, String arg, List options) { boolean seenOption = false; for (String opt: options) { if (opt.equals(option + "=" + arg)) { return true; } else if (opt.equals(option)) { seenOption = true; } else if (seenOption && opt.equals(arg)) { return true; } else { seenOption = false; } } return false; } //----------misc statics---------------------------------------------------- protected static final String FILESEP = System.getProperty("file.separator"); protected static final String LINESEP = System.getProperty("line.separator"); // This is a hack to deal with the fact that the implementation of // Runtime.exec() for Windows stringifies the arguments. protected static final String EXECQUOTE = (System.getProperty("os.name").startsWith("Windows") ? "\"" : ""); public static final String REASON_ASSUMED_ACTION = "ASSUMED_ACTION", REASON_USER_SPECIFIED = "USER_SPECIFIED", REASON_ASSUMED_BUILD = "ASSUMED_BUILD", REASON_FILE_TOO_OLD = "FILE_OUT_OF_DATE"; protected static final String SREASON_ASSUMED_ACTION= "Assumed action based on file name: run ", SREASON_USER_SPECIFIED= "User specified action: run ", SREASON_ASSUMED_BUILD = "Named class compiled on demand", SREASON_FILE_TOO_OLD = ".class file out of date or does not exist"; // These are all of the error messages used in all actions. protected static final String PARSE_TIMEOUT_NONE = "No timeout value", PARSE_TIMEOUT_BAD_INT = "Bad integer specification: ", PARSE_FAIL_UEXPECT = "Unexpected value for `fail': ", PARSE_MODULE_NONE = "No module name", PARSE_MODULE_INVALID = "Invalid module name", // policy and security manager PARSE_BAD_OPT_JDK = "Option not allowed using provided test JDK: ", PARSE_NO_POLICY_NAME = "No policy file name", PARSE_CANT_FIND_POLICY= "Can't find policy file: ", PARSE_NO_SECURE_NAME = "No security manager file name", PARSE_POLICY_OTHERVM = "`/policy' and `/java.security.policy` require use of `/othervm'", PARSE_SECURE_OTHERVM = "`/secure' requires use of `/othervm'", PARSE_TIMEOUT_MANUAL = "`/manual' disables use of `/timeout'", POLICY_WRITE_PROB = "Problems writing new policy file: ", POLICY_SM_PROB = "Unable to create new policy file: ", LOG_COMMAND = "command: ", LOG_RESULT = " result: ", LOG_JT_COMMAND = "JavaTest command: ", LOG_REASON = "reason: ", LOG_ELAPSED_TIME = "elapsed time (seconds): ", LOG_STARTED = "started: ", LOG_FINISHED = "finished: ", //LOG_JDK = "JDK under test: ", // COMMON // used in: shell, main, applet EXEC_FAIL = "Execution failed", EXEC_FAIL_EXPECT = "Execution failed as expected", EXEC_PASS_UNEXPECT = "Execution passed unexpectedly", CHECK_PASS = "Test description appears acceptable", // used in: compile, main AGENTVM_CANT_GET_VM = "Cannot get VM for test", AGENTVM_IO_EXCEPTION = "Agent communication error: %s; check console log for any additional details", AGENTVM_EXCEPTION = "Agent error: %s; check console log for any additional details", CANT_FIND_SRC = "Can't find source file: ", // applet APPLET_ONE_ARG_REQ = "`applet' requires exactly one file argument", APPLET_BAD_VAL_MANUAL = "Bad value for `manual' option: ", APPLET_BAD_OPT = "Bad option for applet: ", APPLET_CANT_FIND_HTML = "Can't find HTML file: ", APPLET_HTML_READ_PROB = "Problem reading HTML file: ", APPLET_MISS_ENDBODY = "No tag in ", APPLET_MISS_APPLET = "No tag in ", APPLET_MISS_ENDAPPLET = "No tag in ", APPLET_MISS_REQ_ATTRIB= " missing required attribute ", APPLET_ARCHIVE_USUPP = "`archive' not supported in file: ", APPLET_MISS_REQ_PARAM = "Missing required name or value for param in tag", APPLET_CANT_WRITE_ARGS= "Can't write `applet' argument file", APPLET_SECMGR_FILEOPS = "Unable to create applet argument file", APPLET_USER_EVAL = ", user evaluated", APPLET_MANUAL_TEST = "Manual test", // build BUILD_UNEXPECT_OPT = "Unexpected options for `build'", BUILD_NO_CLASSNAME = "No classname(s) provided for `build'", BUILD_BAD_CLASSNAME = "Bad classname provided for `build': ", BUILD_NO_COMP_NEED = "No need to compile: ", BUILD_UP_TO_DATE = "All files up to date", BUILD_SUCC = "Build successful", BUILD_LIB_LIST = " in directory-list: ", BUILD_FUTURE_SOURCE = "WARNING: file %s has a modification time in the future: %s", BUILD_FUTURE_SOURCE_2 = "Unexpected results may occur", // clean CLEAN_SUCC = "Clean successful", CLEAN_UNEXPECT_OPT = "Unexpected option(s) for `clean'", CLEAN_NO_CLASSNAME = "No classname(s) provided for `clean'", CLEAN_BAD_CLASSNAME = "Bad classname provided for `clean': ", CLEAN_RM_FAILED = "`clean' unable to delete file: ", CLEAN_SECMGR_PROB = "Problem deleting directory contents: ", // compile COMPILE_NO_CLASSNAME = "No classname provided for `compile'", COMPILE_NO_DOT_JAVA = "No classname ending with `.java' found", COMPILE_BAD_OPT = "Bad option for compile: ", COMPILE_OPT_DISALLOW = "Compile option not allowed: ", COMPILE_NO_REF_NAME = "No reference file name", COMPILE_CANT_FIND_REF = "Can't find reference file: ", COMPILE_CANT_READ_REF = "Can't read reference file: ", COMPILE_GOLD_FAIL = "Output does not match reference file: ", COMPILE_GOLD_LINE = ", line ", COMPILE_GOLD_READ_PROB= "Problem reading reference file: ", COMPILE_MODULES_UEXPECT = "Unexpected value for `modules': ", COMPILE_CANT_CREATE_ARG_FILE = "Can't create `compile' argument file", COMPILE_CANT_WRITE_ARGS = "Can't write `compile' argument file", COMPILE_SECMGR_FILEOPS = "Unable to create `compile' argument file", COMPILE_PASS_UNEXPECT = "Compilation passed unexpectedly", COMPILE_PASS = "Compilation successful", COMPILE_FAIL_EXPECT = "Compilation failed as expected", COMPILE_FAIL = "Compilation failed", COMPILE_CANT_RESET_SECMGR= "Cannot reset security manager", COMPILE_CANT_RESET_PROPS = "Cannot reset system properties", // ignore IGNORE_UNEXPECT_OPTS = "Unexpected option(s) for `ignore'", IGNORE_TEST_IGNORED = "Test ignored", IGNORE_TEST_IGNORED_C = "Test ignored: ", IGNORE_TEST_SUPPRESSED = "@ignore suppressed by command line option", IGNORE_TEST_SUPPRESSED_C = "@ignore suppressed by command line option: ", // junit JUNIT_NO_CLASSNAME = "No class provided for `junit'", JUNIT_BAD_MAIN_ARG = "Bad argument provided for class in `junit'", // driver DRIVER_NO_CLASSNAME = "No class provided for `driver'", DRIVER_UNEXPECT_VMOPT = "VM options not allowed", DRIVER_BAD_OPT = "Bad option for driver: ", // main MAIN_NO_CLASSNAME = "No class provided for `main'", MAIN_MANUAL_NO_VAL = "Arguments to `manual' option not supported: ", MAIN_BAD_OPT = "Bad option for main: ", MAIN_CANT_FIND_SECURE = "Can't find security manager file name: ", MAIN_BAD_OPT_JDK = "Option not allowed using provided test JDK: ", MAIN_NO_POLICY_NAME = "No policy file name", MAIN_CANT_FIND_POLICY = "Can't find policy file: ", MAIN_POLICY_OTHERVM = "`/policy' requires use of `/othervm'", MAIN_NO_SECURE_NAME = "No security manager file name", MAIN_SECURE_OTHERVM = "`/secure' requires use of `/othervm'", MAIN_UNEXPECT_VMOPT = ": vm option(s) found, need to specify /othervm", MAIN_POLICY_WRITE_PROB= "Problems writing new policy file: ", MAIN_POLICY_SM_PROB = "Unable to create new policy file: ", MAIN_CANT_RESET_SECMGR= "Cannot reset security manager", MAIN_CANT_RESET_PROPS = "Cannot reset system properties", MAIN_NO_NATIVES = "Use -nativepath to specify the location of native code", // runOtherJVM MAIN_CANT_WRITE_ARGS = "Can't write `main' argument file", MAIN_SECMGR_FILEOPS = "Unable to create `main' argument file", // shell SHELL_NO_SCRIPT_NAME = "No script name provided for `shell'", SHELL_MANUAL_NO_VAL = "Arguments to `manual' option not supported: ", SHELL_BAD_OPTION = "Bad option for shell: "; //----------member variables------------------------------------------------ protected /*final*/ Map opts; protected /*final*/ List args; protected /*final*/ String reason; protected /*final*/ RegressionScript script; protected /*final*/ TestResult.Section section; protected /*final*/ ActionRecorder recorder; protected /*final*/ PrintWriter configWriter; private long startTime; protected static final boolean showCmd = Flags.get("showCmd"); protected static final boolean showMode = Flags.get("showMode"); protected static final boolean showJDK = Flags.get("showJDK"); } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/exec/ActionRecorder.java000066400000000000000000000155621461415321300306600ustar00rootroot00000000000000/* * Copyright (c) 2013, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.exec; import java.io.File; import java.io.PrintWriter; import java.nio.file.Path; import java.util.List; import java.util.Map; /** * Class to record the commands executed in the course of an Action. */ public class ActionRecorder { ActionRecorder(Action action) { this.action = action; } public void exec(List cmd, Map envArgs) { initPW(); printWorkDir(); // Env variables for (Map.Entry var : envArgs.entrySet()) { pw.println(var.getKey() + "=" + escape(var.getValue()) + CONT); } final int CMD = 1, ARG = 2; int state = CMD; int size = cmd.size(); String indent = " "; String sep = indent; for (int i = 0; i < size; i++) { String word = cmd.get(i); switch (state) { case CMD: pw.print(indent); pw.print(escape(word)); if (i + 1 < size) pw.println(CONT); state = ARG; indent += " "; sep = indent; break; case ARG: if (word.startsWith("-") && sep.equals(" ")) { pw.println(CONT); sep = indent; } pw.print(sep); pw.print(escape(word)); sep = " "; } } pw.println(); } public void exec(String cmd) { initPW(); printWorkDir(); for (String line: cmd.split("[\r\n]+")) pw.println(line); } public void java(Map envArgs, Path javaCmd, Map javaProps, List javaOpts, String className, List classArgs) { initPW(); printWorkDir(); // Env variables for (Map.Entry var : envArgs.entrySet()) { pw.println(var.getKey() + "=" + escape(var.getValue()) + CONT); } // Java executable String indent = " "; pw.println(indent + escape(javaCmd.toString()) + CONT); // System properties indent += " "; for (Map.Entry e: javaProps.entrySet()) { pw.println(indent + "-D" + escape(e.getKey()) + "=" + escape(e.getValue()) + CONT); } // additional JVM options if (javaOpts.size() > 0) { String sep = indent; for (String o : javaOpts) { if (o.startsWith("-") && sep.equals(" ")) { pw.println(CONT); sep = indent; } pw.print(sep); pw.print(escape(o)); sep = " "; } pw.println(CONT); } // class name pw.print(indent + escape(className)); // class args for (String a: classArgs) { pw.print(" "); pw.print(escape(a)); } pw.println(); } void javac(Map envArgs, Path javacCmd, List javacVMOpts, Map javacProps, List javacArgs) { initPW(); printWorkDir(); // Env variables for (Map.Entry var : envArgs.entrySet()) { pw.println(var.getKey() + "=" + escape(var.getValue()) + CONT); } // javac executable String indent = " "; pw.println(indent + escape(javacCmd.toString()) + CONT); indent += " "; // javac VM Options for (String o: javacVMOpts) { pw.println(indent + "-J" + escape(o) + CONT); } // System properties for (Map.Entry e: javacProps.entrySet()) { pw.println(indent + "-J-D" + escape(e.getKey()) + "=" + escape(e.getValue()) + CONT); } String sep = indent; for (String a: javacArgs) { if (a.startsWith("-") && sep.equals(" ")) { pw.println(CONT); sep = indent; } pw.print(sep); pw.print(escape(a)); sep = " "; } pw.println(); } public void asmtools(String toolClassName, List toolArgs) { initPW(); printWorkDir(); String javaHome = System.getProperty("java.home"); String javaCmd = new File(javaHome, "bin/java").toString(); // Java executable String indent = " "; pw.println(indent + escape(javaCmd) + CONT); // additional JVM options pw.println(indent + "-classpath " + action.script.getAsmToolsPath() + CONT); // class name pw.print(indent + escape(toolClassName)); // class args for (String a: toolArgs) { pw.print(" "); pw.print(escape(a)); } pw.println(); } public void close() { if (pw != null) pw.close(); } private void initPW() { if (pw == null) { pw = new PrintWriter(action.section.createOutput("rerun")); } } private String escape(String word) { // simplistic but good enough for now for (int i = 0; i < word.length(); i++) { switch (word.charAt(i)) { case ' ': case '\\': case '$': return "'" + word + "'"; } } return word; } private void printWorkDir() { pw.println("cd " + escape(action.script.absTestScratchDir().toString()) + " &&" + CONT); } private static final String CONT = " \\"; private final Action action; private PrintWriter pw; } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/exec/Agent.java000066400000000000000000001256111461415321300270100ustar00rootroot00000000000000/* * Copyright (c) 2010, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.exec; import java.io.BufferedReader; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.EOFException; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintStream; import java.io.PrintWriter; import java.lang.reflect.Method; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.time.Duration; import java.time.Instant; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.Date; import java.util.Deque; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import java.util.WeakHashMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import com.sun.javatest.Status; import com.sun.javatest.TestResult; import com.sun.javatest.WorkDirectory; import com.sun.javatest.regtest.TimeoutHandler; import com.sun.javatest.regtest.agent.ActionHelper; import com.sun.javatest.regtest.agent.AgentServer; import com.sun.javatest.regtest.agent.Alarm; import com.sun.javatest.regtest.agent.Flags; import com.sun.javatest.regtest.agent.SearchPath; import com.sun.javatest.regtest.config.JDK; import com.sun.javatest.regtest.config.RegressionParameters; import com.sun.javatest.regtest.util.ProcessUtils; import com.sun.javatest.regtest.util.StringUtils; import static com.sun.javatest.regtest.RStatus.createStatus; import static com.sun.javatest.regtest.agent.AgentServer.*; public class Agent { public static class Fault extends Exception { private static final long serialVersionUID = 0; Fault(Throwable e) { super(e); } } // legacy support for logging to stderr // showAgent is superseded by always-on log to file static final boolean showAgent = Flags.get("showAgent"); static final boolean traceAgent = Flags.get("traceAgent"); // the following code here allows us to run jtreg on older // JDKs where the pid() method is unavailable on the // Process class. we use PID only for debug purposes and // the inability to get the PID of a launched AgentServer // is OK. private static final long UNKNOWN_PID = -1; private static final Method PID_METHOD; static { Method pidMethod = null; try { pidMethod = Process.class.getDeclaredMethod("pid"); // only available in Java 9+ } catch (Exception e) { pidMethod = null; } PID_METHOD = pidMethod; } /** * Start a JDK with given JVM options. */ private Agent(File dir, JDK jdk, List vmOpts, Map envVars, File policyFile, float timeoutFactor, Logger logger, String testThreadFactory, String testThreadFactoryPath) throws Fault { Process agentServerProcess = null; try { id = ++count; this.jdk = jdk; this.execDir = dir; this.vmOpts = vmOpts; this.logger = logger; List cmd = new ArrayList<>(); cmd.add(jdk.getJavaProg().toString()); cmd.addAll(vmOpts); if (policyFile != null) cmd.add("-Djava.security.policy=" + policyFile.toURI()); String headless = System.getProperty("java.awt.headless"); if (headless != null) cmd.add("-Djava.awt.headless=" + headless); cmd.add(AgentServer.class.getName()); cmd.add(AgentServer.ID); cmd.add(String.valueOf(id)); cmd.add(AgentServer.LOGFILE); cmd.add(logger.getAgentServerLogFile(id).getPath()); if (policyFile != null) cmd.add(AgentServer.ALLOW_SET_SECURITY_MANAGER); ServerSocket ss = new ServerSocket(); // Ensure SO_REUSEADDR is false. (It is only needed if we're // using a fixed port.) The default setting for SO_REUSEADDR // is platform-specific, and Solaris has it on by default. ss.setReuseAddress(false); InetAddress loopbackAddr = InetAddress.getLoopbackAddress(); ss.bind(new InetSocketAddress(loopbackAddr, /*port:*/ 0), /*backlog:*/ 1); final int port = ss.getLocalPort(); cmd.add(AgentServer.PORT); cmd.add(String.valueOf(port)); if (timeoutFactor != 1.0f) { cmd.add(AgentServer.TIMEOUTFACTOR); cmd.add(String.valueOf(timeoutFactor)); } if (testThreadFactory != null) { cmd.add(AgentServer.CUSTOM_TEST_THREAD_FACTORY); cmd.add(testThreadFactory); } if (testThreadFactoryPath != null) { cmd.add(CUSTOM_TEST_THREAD_FACTORY_PATH); cmd.add(testThreadFactoryPath); } log("Launching " + cmd); ProcessBuilder pb = new ProcessBuilder(cmd); pb.directory(dir); Map env = pb.environment(); env.clear(); env.putAll(envVars); agentServerProcess = process = pb.start(); final long pid = getPid(process); copyAgentProcessStream("stdout", process.getInputStream()); copyAgentProcessStream("stderr", process.getErrorStream()); try { final int ACCEPT_TIMEOUT = (int) (60 * 1000 * timeoutFactor); // default 60 seconds, for server to start and "phone home" ss.setSoTimeout(ACCEPT_TIMEOUT); log("Waiting up to " + ACCEPT_TIMEOUT + " milli seconds for a" + " socket connection on port " + port + (pid != UNKNOWN_PID ? " from process " + pid : "")); Socket s = ss.accept(); log("Received connection on port " + port + " from " + s); s.setSoTimeout((int)(KeepAlive.READ_TIMEOUT * timeoutFactor)); in = new DataInputStream(s.getInputStream()); out = new DataOutputStream(s.getOutputStream()); } finally { ss.close(); } keepAlive = new KeepAlive(out, traceAgent); // send keep-alive messages to server while not executing actions keepAlive.setEnabled(true); } catch (IOException e) { log("Agent creation failed due to " + e); if (agentServerProcess != null) { // kill the launched process log("killing AgentServer process"); try { ProcessUtils.destroyForcibly(agentServerProcess); } catch (Exception ignored) { // ignore } } throw new Fault(e); } } /** * Reads the output written by an agent process, and copies it either to * the current TestResult object (when one is available) or to the agent's * log file, if output is found while there is no test using the agent. * * @param name the name of the stream * @param in the stream */ void copyAgentProcessStream(final String name, final InputStream in) { Thread t = new Thread() { @Override public void run() { try (BufferedReader inReader = new BufferedReader(new InputStreamReader(in))) { String line; while ((line = inReader.readLine()) != null) { handleProcessStreamLine(name, line); } } catch (IOException e) { // ignore } } }; t.setDaemon(true); t.start(); } /** * This field is set during doAction, and when set, any output received * from the agent process on stdout (fd1) and stderr (fd2) will be written * to the appropriate block in the current test result section. * Any data received from the agent when this is not set is written to the * agent log file. */ private TestResult.Section currentTestResultSection; /** * A map of the currently open writers for process streams capturing * output written by the agent on stdout (fd0) and stderr (fd1). */ private Map processStreamWriters = new HashMap<>(); /** * Starts or stops capturing output written by the agent on stdout (fd1) and stderr (fd2) * into the given test result section. * * If the given section is not {code null}, output written by the agent will * be recorded in blocks in the given section. * If the given section is {@code null}, output written by the agent will * be recorded in the agent's log file. * * It is expected that this method will be used to set a non-null section * for the duration of an ac tion (see doAction), so that output written * by the agent during that time will be recorded in the appropriate test * result section. * * @param section the test result section to be used, or {@code null} */ private synchronized void captureProcessStreams(TestResult.Section section) { currentTestResultSection = section; if (currentTestResultSection == null) { for (PrintWriter pw : processStreamWriters.values()) { pw.close(); } processStreamWriters.clear(); } } /** * Saves a line of output that was written by the agent to stdout (fd1) or stderr (fd2). * If there is a current test result section, the line is saved there; * otherwise it is written to the agent log file. * * @param name the name of the stream from which the line was read * @param line the line that was read */ private synchronized void handleProcessStreamLine(String name, String line) { if (currentTestResultSection == null) { log(name + ": " + line); } else { processStreamWriters.computeIfAbsent(name, currentTestResultSection::createOutput) .println(line); } } public boolean matches(File execDir, JDK jdk, List vmOpts) { return this.execDir.getName().equals(execDir.getName()) && this.jdk.equals(jdk) && this.vmOpts.equals(vmOpts); } public Status doCompileAction( final String testName, final Map testProps, final List cmdArgs, int timeout, final TimeoutHandler timeoutHandler, TestResult.Section trs) throws Fault { trace("doCompileAction " + testName + " " + cmdArgs); return doAction("doCompileAction", new AgentAction() { @Override public void send() throws IOException { // See corresponding list in AgentServer.doCompile out.writeByte(DO_COMPILE); out.writeUTF(testName); writeMap(testProps); writeCollection(cmdArgs); out.flush(); } }, timeout, timeoutHandler, trs); } public Status doMainAction( final String testName, final Map testProps, final Set addExports, final Set addOpens, final Set addMods, final SearchPath testClassPath, final SearchPath modulePath, final String testClass, final List testArgs, int timeout, final TimeoutHandler timeoutHandler, TestResult.Section trs) throws Fault { trace("doMainAction: " + testName + " " + testClassPath + " " + modulePath + " " + testClass + " " + testArgs); return doAction("doMainAction", new AgentAction() { @Override public void send() throws IOException { // See corresponding list in AgentServer.doMain out.writeByte(DO_MAIN); out.writeUTF(testName); writeMap(testProps); writeCollection(addExports); writeCollection(addOpens); writeCollection(addMods); out.writeUTF(testClassPath.toString()); out.writeUTF(modulePath.toString()); out.writeUTF(testClass); writeCollection(testArgs); out.flush(); } }, timeout, timeoutHandler, trs); } interface AgentAction { void send() throws IOException; } private Status doAction( String actionName, AgentAction agentAction, int timeout, final TimeoutHandler timeoutHandler, TestResult.Section trs) throws Fault { final PrintWriter messageWriter = trs.getMessageWriter(); // Handle the timeout here (instead of in the agent) to make it possible // to see the unchanged state of the Agent JVM when the timeout happens. Alarm alarm = Alarm.NONE; final CountDownLatch timeoutHandlerDone = new CountDownLatch(1); if (timeout > 0) { if (timeoutHandler == null) { throw new NullPointerException("TimeoutHandler is required"); } trace(actionName + ": scheduling timeout handler in " + timeout + " seconds"); alarm = Alarm.schedule(timeout, TimeUnit.SECONDS, messageWriter, new Runnable() { @Override public void run() { invokeTimeoutHandler(timeoutHandler, timeoutHandlerDone, messageWriter); } }); } keepAlive.setEnabled(false); try { captureProcessStreams(trs); synchronized (out) { agentAction.send(); } trace(actionName + ": request sent"); return readResults(trs); } catch (IOException e) { trace(actionName + ": error " + e); throw new Fault(e); } finally { captureProcessStreams(null); alarm.cancel(); keepAlive.setEnabled(true); if (alarm.didFire()) { waitForTimeoutHandler(actionName, timeoutHandler, timeoutHandlerDone); throw new Fault(new Exception("Agent " + id + " timed out with a timeout of " + timeout + " seconds")); } } } private void invokeTimeoutHandler(final TimeoutHandler timeoutHandler, final CountDownLatch timeoutHandlerDone, final PrintWriter messageWriter) { // Invocations from an Alarm call should be quick so that the Alarm thread pool // is not consumed. Because of that, we launch the timeout handling in a // separate Thread here. Timeout handling can take a very long time. Thread timeoutHandlerThread = new Thread() { @Override public void run() { trace("timeout handler triggered"); timeoutHandler.handleTimeout(process); // close the streams to release us from readResults() try { out.close(); } catch (IOException ex) { ex.printStackTrace(messageWriter); } try { in.close(); } catch (IOException ex) { ex.printStackTrace(messageWriter); } trace("timeout handler finished"); timeoutHandlerDone.countDown(); } }; timeoutHandlerThread.setName("Timeout Handler for Agent " + getId()); timeoutHandlerThread.start(); } private void waitForTimeoutHandler(String actionName, TimeoutHandler timeoutHandler, CountDownLatch timeoutHandlerDone) { trace(actionName + ": waiting for timeout handler to complete."); try { if (timeoutHandler.getTimeout() <= 0) { timeoutHandlerDone.await(); } else { boolean done = timeoutHandlerDone.await(timeoutHandler.getTimeout() + 10, TimeUnit.SECONDS); if (!done) { trace(actionName + ": timeout handler did not complete within its own timeout."); } } } catch (InterruptedException e1) { trace(actionName + ": interrupted while waiting for timeout handler to complete: " + e1); } } public void close() { log("Closing..."); keepAlive.finished(); try { out.write(CLOSE); // attempt clean shutdown out.close(); } catch (IOException e) { trace("Killing process (" + e + ")"); ProcessUtils.destroyForcibly(process); // force shutdown if necessary } PrintWriter pw = new PrintWriter(System.err, true); Alarm alarm = Alarm.schedulePeriodicInterrupt(60, TimeUnit.SECONDS, pw, Thread.currentThread()); try { int rc = process.waitFor(); if (rc != 0) trace("Exited, process exit code: " + rc); } catch (InterruptedException e) { log("Interrupted while closing"); log("Killing process"); ProcessUtils.destroyForcibly(process); } finally { alarm.cancel(); Thread.interrupted(); // clear any interrupted status } log("Closed"); } void writeCollection(Collection c) throws IOException { out.writeShort(c.size()); for (String s: c) out.writeUTF(s); } void writeOptionalString(String s) throws IOException { if (s == null) out.writeByte(0); else { out.writeByte(1); out.writeUTF(s); } } static String readOptionalString(DataInputStream in) throws IOException { int b = in.readByte(); return (b == 0) ? null : in.readUTF(); } void writeMap(Map map) throws IOException { out.writeShort(map.size()); for (Map.Entry e: map.entrySet()) { out.writeUTF(e.getKey()); out.writeUTF(e.getValue()); } } Status readResults(TestResult.Section trs) throws IOException { Map streams = new HashMap<>(); int op; while ((op = in.readByte()) != -1) { switch (op) { case OUTPUT: { String name = in.readUTF(); String data = in.readUTF(); trace("readResults: OUTPUT \'" + name + "\' \'" + data + "\""); PrintWriter pw = streams.get(name); if (pw == null) { if (name.equals(ActionHelper.OutputHandler.OutputKind.LOG.name)) pw = trs.getMessageWriter(); else pw = trs.createOutput(name); streams.put(name, pw); } pw.write(data); break; } case STATUS: { int type = in.readByte(); String reason = in.readUTF(); trace("readResults: STATUS \'" + type + "\' \'" + reason + "\""); for (PrintWriter pw: streams.values()) { if (pw != trs.getMessageWriter()) pw.close(); } Status status = createStatus(type, reason); // any other cleanup?? return status; } case KEEPALIVE: break; default: // mark owner bad?? // do { // System.err.println("Unexpected op: " + op + "'" + ((char)op) + "'"); // } while ((op = in.readByte()) != -1); // Thread.dumpStack(); throw new IOException("Agent: unexpected op: " + op); } } // mark owner bad?? throw new EOFException("unexpected EOF"); } /** * Returns the id for this agent. * The id is just a small strictly-positive integer, allocated from 1 on up. * The id is used to identify the agent in logging messages. * * @return the id */ public int getId() { return id; } /** * Logs a message to the log file managed by the logger. * * @param message the message */ private void log(String message) { logger.log(this, message); show(message); } private void show(String s) { if (showAgent || traceAgent) { log(s, System.err); } } private void trace(String s) { if (traceAgent) { log(s, System.err); } } // legacy show/trace support private void log(String message, PrintStream out) { out.println("[" + AgentServer.logDateFormat.format(new Date()) + "] Agent[" + getId() + "]: " + message); } private static long getPid(final Process process) { if (PID_METHOD == null) { return UNKNOWN_PID; } try { return (long) PID_METHOD.invoke(process); } catch (Exception e) { return UNKNOWN_PID; } } final JDK jdk; final List vmOpts; final File execDir; final Process process; final DataInputStream in; final DataOutputStream out; final KeepAlive keepAlive; final int id; final Logger logger; Instant idleStartTime; static int count; /** * Logger provides a directory ion which log files can be created, * and a writer for writing client-side logging messages. * The directory is the system jtData directory in the work directory; * The file for client-side logging is jtData/agent.trace. * Log messages are prefixed with a standard sort-friendly timestamp, * so that the log files in the directory can be merge-sorted into * a single log for later analysis. */ public static class Logger { private static WeakHashMap instances = new WeakHashMap<>(); public static synchronized Logger instance(RegressionParameters params) { return instances.computeIfAbsent(params, Logger::new); } public static void close(RegressionParameters params) throws IOException { Logger l = instances.get(params); if (l != null) { l.close(); } } private File agentLogFileDirectory; private final PrintWriter agentLogWriter; Logger(RegressionParameters params) { WorkDirectory wd = params.getWorkDirectory(); agentLogFileDirectory = wd.getJTData(); File logFile = new File(agentLogFileDirectory, "agent.trace"); PrintWriter out; try { out = new PrintWriter(new FileWriter(logFile)); } catch (IOException e) { System.err.println("Cannot open agent log file: " + e); out = new PrintWriter(System.err, true) { @Override public void close() { flush(); } }; } agentLogWriter = out; } void log(Agent agent, String message) { String dateInfo = AgentServer.logDateFormat.format(new Date()); String agentInfo = (agent == null) ? "" : " Agent[" + agent.getId() + "]"; if (message.contains("\n")) { String[] lines = message.split("\\R"); int i = 0; for (String line : lines) { agentLogWriter.printf("[%s]%s: #%d/%d %s%n", dateInfo, agentInfo, ++i, lines.length, line); } } else { agentLogWriter.printf("[%s]%s: %s%n", dateInfo, agentInfo, message); } } File getAgentServerLogFile(int id) { return new File(agentLogFileDirectory, "agentServer." + id + ".trace"); } public void close() throws IOException { agentLogWriter.close(); } } /** * A reusable collection of JVMs with varying VM options. *

* Pools are associated with an instance of RegressionParameters, from which * it gets a Logger to report activity that may be useful in case of any problems. */ public static class Pool { /** * The instances. * It is expected that there will typically be exactly one entry in this collection. */ private static WeakHashMap instances = new WeakHashMap<>(); private Stats stats = new Stats(); /** * Returns the instance for the given RegressionParameters object. * * @param params the RegressionParameters object * @return the instance */ public static synchronized Pool instance(RegressionParameters params) { return instances.computeIfAbsent(params, Pool::new); } private Pool(RegressionParameters params) { agentsByKey = new HashMap<>(); allAgents = new LinkedList<>(); logger = Logger.instance(params); } /** * Sets the policy file to be used for agents created for this pool. * * @param policyFile the file */ public void setSecurityPolicy(File policyFile) { this.policyFile = policyFile; } /** * Sets the timeout factor to be used for agents created for this pool. * * @param factor the timeout factor */ public void setTimeoutFactor(float factor) { this.timeoutFactor = factor; } /** * Sets the idle timeout for VMs in the pool. * * @param timeout the timeout */ public void setIdleTimeout(Duration timeout) { this.idleTimeout = timeout; logger.log(null, "POOL: idle timeout: " + timeout); } /** * Sets the maximum number of VMs in the pool. * * @param size the maximum number of VMs to keep in the pool */ public void setMaxPoolSize(int size) { this.maxPoolSize = size; logger.log(null, "POOL: max pool size: " + maxPoolSize); } /** * Sets the maximum attempts to create or obtain an agent VM * @param numAttempts number of attempts * @throws IllegalArgumentException if {@code numAttempts} is less than {@code 1} */ public void setNumAgentSelectionAttempts(final int numAttempts) { if (numAttempts < 1) { throw new IllegalArgumentException("invalid value for agent selection attempts: " + numAttempts); } this.numAgentSelectionAttempts = numAttempts; logger.log(null, "POOL: agent selection attempts: " + numAttempts); } /** * Obtains an agent with the desired properties. * If a suitable agent already exists in the pool, it will be removed from the pool and * returned; otherwise, a new one will be created. * Eventually, the agent should either be {@link #save(Agent) returned} to the pool, * if it can be reused, or {@link Agent#close() closed}, if it should not be reused. * * * @param dir the execution directory for the agent * @param jdk the JDK for the agent * @param vmOpts the VM options for the agent * @param envVars the environment variables for the agent * @return the agent * @throws Fault if there is a problem obtaining a suitable agent */ Agent getAgent(File dir, JDK jdk, List vmOpts, Map envVars, String testThreadFactory, String testThreadFactoryPath) throws Fault { final int numAttempts = this.numAgentSelectionAttempts; assert numAttempts > 0 : "unexpected agent selection attempts: " + numAttempts; Agent.Fault toThrow = null; for (int i = 1; i <= numAttempts; i++) { try { if (i != 1) { logger.log(null, "POOL: re-attempting agent creation, attempt number " + i); } return doGetAgent(dir, jdk, vmOpts, envVars, testThreadFactory, testThreadFactoryPath); } catch (Agent.Fault f) { logger.log(null, "POOL: agent creation failed due to " + f.getCause()); // keep track of the fault and reattempt to get an agent if within limit if (toThrow == null) { toThrow = f; } else { // add the previous exception as a suppressed exception // of the current one if (toThrow.getCause() != null) { f.addSuppressed(toThrow.getCause()); } toThrow = f; } if (i == numAttempts || !(f.getCause() instanceof IOException)) { // we either made enough attempts or we failed due to a non IOException. // In either case we don't attempt to create an agent again and instead // throw the captured failure(s) throw toThrow; } } } throw new AssertionError("should not reach here"); } synchronized Agent doGetAgent(File dir, JDK jdk, List vmOpts, Map envVars, String testThreadFactory, String testThreadFactoryPath) throws Fault { logger.log(null, "POOL: get agent for:\n" + " directory: " + dir + "\n" + " JDK: " + jdk + "\n" + " VM options: " + vmOpts + "\n" ); Deque agents = agentsByKey.get(getKey(dir, jdk, vmOpts)); // reuse the most recently used agent, to increase the possibility // that older, less-used agents can be reclaimed. Agent a = (agents == null) ? null : agents.pollLast(); if (a != null) { logger.log(null, "POOL: Reusing Agent[" + a.getId() + "]"); allAgents.remove(a); stats.reuse(a); } else { logger.log(null, "POOL: Creating new agent"); a = new Agent(dir, jdk, vmOpts, envVars, policyFile, timeoutFactor, logger, testThreadFactory, testThreadFactoryPath); stats.add(a); } return a; } /** * Saves an agent in the pool for potential reuse. * The agent is assumed to have been restored to some standard state. * * @param agent the agent */ synchronized void save(Agent agent) { logger.log(agent, "Saving agent to pool"); String key = getKey(agent.execDir, agent.jdk, agent.vmOpts); agentsByKey.computeIfAbsent(key, k -> new LinkedList<>()).add(agent); allAgents.addLast(agent); Instant now = Instant.now(); agent.idleStartTime = now; cleanOldEntries(now); stats.trackPoolSize(allAgents.size()); } /** * Remove any old entries from the pool. * * The current policy is to remove excess agents when there are too many, * and to remove any agents that have been idle too long. * The maximum number of agents in the pool, and the maximum idle time * are both configurable. * * @param now the current time */ private synchronized void cleanOldEntries(Instant now) { while (allAgents.size() > maxPoolSize) { Agent a = allAgents.getFirst(); logger.log(a, "Removing excess agent from pool"); removeAgent(a); } while (!allAgents.isEmpty() && isIdleTooLong(allAgents.peekFirst(), now)) { Agent a = allAgents.getFirst(); logger.log(a, "Removing idle agent from pool"); removeAgent(a); } } private void removeAgent(Agent a) { agentsByKey.get(getKey(a)).remove(a); allAgents.remove(a); a.close(); } private boolean isIdleTooLong(Agent a, Instant now) { return Duration.between(a.idleStartTime, now).compareTo(idleTimeout) > 0; } /** * Flushes any agents that may have been saved in a pool associated with * the given RegressionParameters object. * * @param params the RegressionParameters object */ public static synchronized void flush(RegressionParameters params) { Pool instance = instances.get(params); if (instance != null) { instance.flush(); } } /** * Flushes all agents that have been saved in this pool. */ public synchronized void flush() { logger.log(null, "POOL: closing all agents"); for (Agent a : allAgents) { a.close(); } allAgents.clear(); agentsByKey.clear(); stats.report(new File(logger.agentLogFileDirectory, "agent.summary"), logger); } /** * Closes any agents with a given execution directory that may have been saved in a pool * associated with the given RegressionParameters object. * * @param params the RegressionParameters object * @param dir the execution directory */ static synchronized void close(RegressionParameters params, File dir) { Pool instance = instances.get(params); if (instance != null) { instance.close(dir); } } /** * Closes all agents in this pool with the given execution directory. * This is for use when the directory is no longer suitable for use, * such as when containing a file that cannot be deleted. * * @param dir the execution directory */ synchronized void close(File dir) { logger.log(null, "POOL: closing agents using directory " + dir); for (Iterator iter = allAgents.iterator(); iter.hasNext(); ) { Agent agent = iter.next(); if (agent.execDir.equals(dir)) { // remove from the allAgents list, currently being iterated iter.remove(); // remove from the agentsByKey map String agentKey = getKey(agent); Deque deque = agentsByKey.get(agentKey); deque.remove(agent); if (deque.isEmpty()) { agentsByKey.remove(agentKey); } // close the agent agent.close(); } } } private static String getKey(Agent agent) { return getKey(agent.execDir, agent.jdk, agent.vmOpts); } private static String getKey(File dir, JDK jdk, List vmOpts) { return (dir.getAbsolutePath() + " " + jdk.getAbsoluteHomeDirectory() + " " + StringUtils.join(vmOpts, " ")); } private final Logger logger; /** * A map of the currently available agents, indexed by a key * derived from the agent's primary execution characteristics. * For each key, a deque is maintained of agents with that key. * The most recently used entries are "last" in the deque; * the oldest entries are "first" in the deque. */ private final Map> agentsByKey; /** * A list of all the currently available agents. * The most recently used entries are "last" in the deque; * the oldest entries are "first" in the deque. */ private final Deque allAgents; private File policyFile; private float timeoutFactor = 1.0f; private int maxPoolSize; private Duration idleTimeout; private int numAgentSelectionAttempts; } static class Stats { Set allDirs = new TreeSet<>(); Set allJDKs = new TreeSet<>(Comparator.comparing( j -> j.getPath())); Set> allVMOpts = new TreeSet<>(Comparator.comparing(Objects::toString)); Map useCounts = new TreeMap<>(); Map sizeCounts = new TreeMap<>(); void add(Agent a) { allDirs.add(a.execDir); allJDKs.add(a.jdk); allVMOpts.add(a.vmOpts); useCounts.put(a.id, 1); } void reuse(Agent a) { useCounts.put(a.id, useCounts.get(a.id) + 1); } void trackPoolSize(int size) { sizeCounts.put(size, sizeCounts.computeIfAbsent(size, s -> 0) + 1); } void clear() { allDirs.clear(); allJDKs.clear(); allVMOpts.clear(); useCounts.clear(); sizeCounts.clear(); } void report(File file, Logger logger) { try (PrintWriter out = new PrintWriter(new FileWriter(file))) { report(out, "Execution Directories", allDirs); out.println(); report(out, "JDKs", allJDKs); out.println(); report(out, "VM Options", allVMOpts); out.println(); out.format("Agent Usage:%n"); useCounts.forEach((id, c) -> out.format(" %3d: %3d%n", id, c)); double[] use_m_sd = getSimpleMeanStandardDeviation(useCounts.values()); out.format("Mean: %5.1f%n", use_m_sd[0]); out.format("Std Deviation: %5.1f%n", use_m_sd[1]); out.println(); out.format("Pool Size:%n"); sizeCounts.forEach((size, c) -> out.format(" %3d: %3d%n", size, c)); double[] size_m_sd = getWeightedMeanStandardDeviation(sizeCounts); out.format("Mean %5.1f%n", size_m_sd[0]); out.format("Std Deviation %5.1f%n", size_m_sd[1]); } catch (IOException e) { logger.log(null, "STATS: can't write stats file " + file + ": " + e); } } private void report(PrintWriter out, String title, Set set) { out.format("%s: %d%n", title, set.size()); set.forEach(item -> out.format(" %s%n", item)); } /** * Returns the mean and standard deviation of a collection of values. * * @param values the values * @return an array containing the mean and standard deviation */ double[] getSimpleMeanStandardDeviation(Collection values) { double sum = 0; for (Integer v : values) { sum += v; } double mean = sum / values.size(); double sum2 = 0; for (Integer v : values) { double x = v - mean; sum2 += x * x; } double sd = Math.sqrt(sum2 / values.size()); return new double[] { mean, sd }; } /** * Returns the mean and standard deviation of a collection of weighted values. * The values are provided in a map of {@code value -> frequency}. * * @param map the map of weighted values * @return an array containing the mean and standard deviation */ double[] getWeightedMeanStandardDeviation(Map map) { long count = 0; double sum = 0; for (Map.Entry e : map.entrySet()) { int value = e.getKey(); int freq = e.getValue(); sum += value * freq; count += freq; } double mean = sum / count; double sum2 = 0; for (Map.Entry e : map.entrySet()) { int value = e.getKey(); int freq = e.getValue(); double x = value - mean; sum2 += x * x * freq; } double sd = Math.sqrt(sum2 / count); return new double[] { mean, sd }; } } } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/exec/AppletAction.java000066400000000000000000000612701461415321300303350ustar00rootroot00000000000000/* * Copyright (c) 1998, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.exec; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.io.Writer; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; import com.sun.javatest.Status; import com.sun.javatest.regtest.TimeoutHandler; import com.sun.javatest.regtest.agent.AppletWrapper; import com.sun.javatest.regtest.agent.SearchPath; import com.sun.javatest.regtest.config.JDKOpts; import com.sun.javatest.regtest.config.Modules; import com.sun.javatest.regtest.config.ParseException; import com.sun.javatest.regtest.exec.RegressionScript.PathKind; import static com.sun.javatest.regtest.RStatus.*; /** * This class implements the "applet" action as described by the JDK tag * specification. * * @see Action */ public class AppletAction extends Action { public static final String NAME = "applet"; /** * {@inheritDoc} * @return "applet" */ @Override public String getName() { return NAME; } /** * This method does initial processing of the options and arguments for the * action. Processing is determined by the requirements of run(). * * Verify that the options are valid for the "applet" action. * * Verify that there is at least one argument. This is assumed to be the * html file name. * * @param opts The options for the action. * @param args The arguments for the actions. * @param reason Indication of why this action was invoked. * @param script The script. * @exception ParseException If the options or arguments are not expected * for the action or are improperly formated. */ @Override public void init(Map opts, List args, String reason, RegressionScript script) throws ParseException { super.init(opts, args, reason, script); if (args.size() != 1) throw new ParseException(APPLET_ONE_ARG_REQ); for (Map.Entry e: opts.entrySet()) { String optName = e.getKey(); String optValue = e.getValue(); switch (optName) { case "fail": reverseStatus = parseFail(optValue); break; case "timeout": timeout = parseTimeout(optValue); break; case "manual": manual = parseAppletManual(optValue); break; case "othervm": othervm = true; break; case "policy": overrideSysPolicy = true; policyFN = parsePolicy(optValue); break; case "java.security.policy": String name = optValue; if (optValue.startsWith("=")) { overrideSysPolicy = true; name = optValue.substring(1); } policyFN = parsePolicy(name); break; case "secure": secureFN = parseSecure(optValue); break; default: throw new ParseException(APPLET_BAD_OPT + optName); } } if (manual.equals("unset")) { if (timeout < 0) timeout = script.getActionTimeout(-1); } else { if (timeout >= 0) // can't have both timeout and manual throw new ParseException(PARSE_TIMEOUT_MANUAL); timeout = 0; } if (!othervm) { if (policyFN != null) throw new ParseException(PARSE_POLICY_OTHERVM); if (secureFN != null) throw new ParseException(PARSE_SECURE_OTHERVM); } htmlFN = args.get(0); } // init() @Override public Set getSourceFiles() { return Set.of(script.absTestSrcDir().resolve(htmlFN).toFile()); } /** * The method that does the work of the action. The necessary work for the * given action is defined by the tag specification. * * Run the applet described by the first "{@code }" html tag in the given * html file. Equivalent to "appletviewer {@code }". * * Note that currently, this action assumes that the JVM supports multiple * processes. * * @return The result of the action. * @exception TestRunException If an unexpected error occurs while running * the test. */ @Override public Status run() throws TestRunException { Status status; htmlFileContents = new HTMLFileContents(htmlFN); // TAG-SPEC: "The named will be compiled on demand, just as // though an "@run build " action had been inserted before // this action." clsName = htmlFileContents.getAppletAttrs().get("code"); if (clsName.endsWith(".class")) clsName = clsName.substring(0, clsName.lastIndexOf(".class")); Map buildOpts = Collections.emptyMap(); List buildArgs = List.of(clsName); BuildAction ba = new BuildAction(); if (!(status = ba.build(buildOpts, buildArgs, SREASON_ASSUMED_BUILD, script)).isPassed()) return status; startAction(false); if (script.isCheck()) { // If we're only running check on the contents of the test // desciption and we got this far, we can just return success. // Everything after this point is preparation to run the actual test // and the test itself. status = passed(CHECK_PASS); } else { status = runOtherJVM(); } endAction(status); return status; } // run() //----------internal methods------------------------------------------------ private Status runOtherJVM() throws TestRunException { Map execPaths = script.getExecutionPaths(false, null, false, true); Map compatExecPaths = script.getExecutionPaths(false, null, false, false); // WRITE ARGUMENT FILE File argFile = getArgFile(); try (Writer w = new BufferedWriter(new FileWriter(argFile))) { w.write(clsName + "\0"); w.write(script.absTestSrcDir() + "\0"); // not used by AppletWrapper w.write(script.absTestClsDir() + "\0"); // not used by AppletWrapper w.write(compatExecPaths.get(PathKind.CLASSPATH) + "\0"); // not used by AppletWrapper w.write(manual + "\0"); w.write(htmlFileContents.getBody() + "\0"); w.write(toString(htmlFileContents.getAppletParams()) + "\0"); w.write(toString(htmlFileContents.getAppletAttrs()) + "\0"); } catch (IOException e) { return error(APPLET_CANT_WRITE_ARGS); } // CONSTRUCT THE COMMAND LINE // TAG-SPEC: "The source and class directories of a test are made // available to main and applet actions via the system properties // "test.src" and "test.classes", respectively" List command = new ArrayList<>(6); Map env = new LinkedHashMap<>(); command.add(script.getJavaProg().toString()); command.add("-classpath"); command.add(execPaths.get(PathKind.CLASSPATH).toString()); JDKOpts vmOpts = new JDKOpts(); vmOpts.addAll(getExtraModuleConfigOptions(Modules.Phase.DYNAMIC)); vmOpts.addAll(script.getTestVMJavaOptions()); vmOpts.addAll(script.getTestDebugOptions()); command.addAll(vmOpts.toList()); for (Map.Entry e: script.getTestProperties().entrySet()) { command.add("-D" + e.getKey() + "=" + e.getValue()); } String headless = System.getProperty("java.awt.headless"); if (headless != null) command.add("-Djava.awt.headless=" + headless); // input methods use lots of memory boolean mx = false; for (String opt: vmOpts.toList()) { if (opt.startsWith("-mx") || opt.startsWith("-Xmx")) { mx = true; break; } } if (!mx) command.add("-mx128m"); if (policyFN != null) { // add pemission to read JTwork/classes by adding a grant entry File newPolicyFN = addGrantEntries(policyFN); String cmd = overrideSysPolicy ? "-Djava.security.policy==" + newPolicyFN : "-Djava.security.policy=" + newPolicyFN; command.add(cmd); } if (secureFN != null) command.add("-Djava.security.manager=" + secureFN); else if (policyFN != null) command.add("-Djava.security.manager=default"); // command.add("-Djava.security.debug=all"); command.add(AppletWrapper.class.getName()); command.add(argFile.getPath()); env.putAll(script.getEnvVars()); Status status; try (PrintWriter sysOut = section.createOutput("System.out"); PrintWriter sysErr = section.createOutput("System.err")) { if (showCmd) showCmd("applet", command, section); recorder.exec(command, env); // RUN THE APPLET WRAPPER CLASS ProcessCommand cmd = new ProcessCommand(); cmd.setExecDir(script.absTestScratchDir().toFile()); // Set the exit codes and their associated strings. Note that we // require the use of a non-zero exit code for a passed test so // that we have a chance of detecting whether the test itself has // illegally called System.exit(0). cmd.setStatusForExit(Status.exitCodes[Status.PASSED], passed(EXEC_PASS)); cmd.setStatusForExit(Status.exitCodes[Status.FAILED], failed(EXEC_FAIL)); cmd.setDefaultStatus(failed(UNEXPECT_SYS_EXIT)); TimeoutHandler timeoutHandler = script.getTimeoutHandlerProvider().createHandler(this.getClass(), script, section); cmd.setCommand(command) .setEnvironment(env) .setStreams(sysOut, sysErr) .setTimeout(timeout, TimeUnit.SECONDS) .setTimeoutHandler(timeoutHandler); // allow only one applet to run at a time, we don't want the tester // to be inundated with applet tests synchronized (appletLock) { status = normalize(cmd.exec()); } } // EVALUATE RESULTS if (!status.isError() && !status.getReason().startsWith(UNEXPECT_SYS_EXIT)) { // Dynamically construct the return status // an empty reason indicates that the test ran to completion // (either pass or user selected "fail") String sr; if (status.getReason().equals("")) { boolean uEval = manual.equals("yesno"); boolean manualp = (manual.equals("yesno") || manual.equals("done")); String uEvalString = uEval ? APPLET_USER_EVAL : ""; sr = manualp ? (APPLET_MANUAL_TEST + uEvalString + ": ") : ""; } else { sr = ""; } boolean ok = status.isPassed(); int st = status.getType(); if (ok && reverseStatus) { sr += EXEC_PASS_UNEXPECT; st = Status.FAILED; } else if (ok && !reverseStatus) { sr += EXEC_PASS; } else if (!ok && reverseStatus) { sr += EXEC_FAIL_EXPECT; st = Status.PASSED; } else { /* !ok && !reverseStatus */ sr += EXEC_FAIL; } if ((st == Status.FAILED) && !status.getReason().equals("") && !status.getReason().equals(EXEC_PASS)) sr += ": " + status.getReason(); status = createStatus(st, sr); } return status; } // runOtherJVM() private String parseAppletManual(String value) throws ParseException { if (value == null) return "novalue"; if (!value.equals("yesno") && !value.equals("done")) throw new ParseException(APPLET_BAD_VAL_MANUAL + value); return value; } // parseAppletManual() private static String toString(Map d) { StringBuilder retVal = new StringBuilder(); for (Map.Entry e : d.entrySet()) { retVal.append(e.getKey()); retVal.append("\034"); retVal.append(e.getValue()); retVal.append("\034"); } return retVal.toString(); } // toString() //-----internal classes----------------------------------------------------- /** * This class is a view of an HTML file that provides convenient accessor * methods relating to the first HTML applet tag. */ private class HTMLFileContents { /** * @param htmlFN A string describing the relative location of the .html * file. */ HTMLFileContents(String htmlFN) throws TestRunException { // READ THE HTML FILE INTO A STRING String line; StringBuilder sb = new StringBuilder(); //String htmlFN = script.relTestSrcDir() + FILESEP + args[0]; htmlFN = script.absTestSrcDir().resolve(htmlFN).toString(); try (BufferedReader in = new BufferedReader(new FileReader(htmlFN))) { while ((line = in.readLine()) != null) { sb.append(line); sb.append(LINESEP); } } catch (FileNotFoundException e) { throw new TestRunException(APPLET_CANT_FIND_HTML + htmlFN); } catch (IOException e) { throw new TestRunException(APPLET_HTML_READ_PROB + htmlFN); } String contents = sb.toString(); String lower = contents.toLowerCase(); // BODY // If exists, text will be the text between and // . // If does not exist, this is still a valid html file, so // display the entire file. String lowerBody; int[] bodyPos = getTagPositions(contents, lower, "body", 0); if (bodyPos == null) { // no tag, so take the entire file body = contents; lowerBody = lower; } else { int[] endBodyPos = getTagPositions(contents, lower, "/body", bodyPos[3]-1); if (endBodyPos == null) throw new ParseException(APPLET_MISS_ENDBODY + htmlFN); body = contents.substring(bodyPos[3], endBodyPos[0]); lowerBody = lower.substring(bodyPos[3], endBodyPos[0]); } // APPLET ATTRIBUTES // Find the first tag and put contents into a map. int[] appletPos = getTagPositions(body, lowerBody, "applet", 0); if (appletPos == null) throw new ParseException(APPLET_MISS_APPLET + htmlFN); int[] endAppletPos = getTagPositions(body, lowerBody, "/applet", appletPos[3]-1); if (endAppletPos == null) throw new ParseException(APPLET_MISS_ENDAPPLET + htmlFN); appletAttrs = parseAttrs(body.substring(appletPos[1], appletPos[2])); // verify that all of the required attributes are present String[] requiredAtts = {"code", "width", "height"}; for (String requiredAtt : requiredAtts) { if (appletAttrs.get(requiredAtt) == null) { throw new ParseException(htmlFN + APPLET_MISS_REQ_ATTRIB + requiredAtt); } } // We currently do not support "archive". if (appletAttrs.get("archive") != null) throw new ParseException(APPLET_ARCHIVE_USUPP + htmlFN); // APPLET PARAMS // Put all parameters found between and into the // appletParams map. String appletBody = body.substring(appletPos[3], endAppletPos[0]); String lowerAppletBody = appletBody.toLowerCase(); int startPos = 0; int[] paramPos; while ((paramPos = getTagPositions(appletBody, lowerAppletBody, "param", startPos)) != null) { Map d = parseAttrs(appletBody.substring(paramPos[1], paramPos[2])); String name = d.get("name"); String value = d.get("value"); if ((name == null) || (value == null)) throw new ParseException(APPLET_MISS_REQ_PARAM); appletParams.put(name, value); startPos = paramPos[3]; } } // HTMLFileContents() //----------accessor methods-------------------------------------------- String getBody() { return body; } // getBody() Map getAppletParams() { return appletParams; } // getAppletParams() Map getAppletAttrs() { return appletAttrs; } // getAppletAttrs() //----------internal methods-------------------------------------------- /** * Return "important" positions used in parsing HTML tag attributes. * *
         *  f o o    = b a r
         * ^     ^    ^     ^
         * 0     1    2     3
         * 
* * @param attrs A string containing attributes. * @return Array of four interesting positions for the first attribute * in the string. */ private int[] getAttrPositions(String attrs, int startPos) { try { // find the start of the name, skipping any header whitespace int nameStart = startPos; while (Character.isWhitespace(attrs.charAt(nameStart))) nameStart++; // the name ends at the first whitespace or '=' int nameEnd = nameStart; while (true) { char c = attrs.charAt(nameEnd); if (Character.isWhitespace(c) || (c == '=')) break; nameEnd++; } // hop over any whitespaces to find the '=' int valStart = nameEnd; while (Character.isWhitespace(attrs.charAt(valStart))) valStart++; // verify presence of '=' if (attrs.charAt(valStart) != '=') return null; valStart++; // hop over any whitespaces after the '=' to find valStart while (Character.isWhitespace(attrs.charAt(valStart))) valStart++; // find valEnd by locating the first non-quoted whitespace // character or the end of the string int theEnd = attrs.length(); int valEnd = valStart; boolean inString = false; while (valEnd < theEnd) { char c = attrs.charAt(valEnd); if (!inString && Character.isWhitespace(c)) break; if (c == '"') inString = !inString; if ((c == '\\') && (valEnd < (theEnd - 1))) valEnd++; valEnd++; } // verify that attribute is valid if ((nameEnd <= nameStart) || (valEnd <= valStart)) return null; return new int[] { nameStart, nameEnd, valStart, valEnd }; } catch (StringIndexOutOfBoundsException e) { return null; // input string was of invalid format } } // getAttrPositions() /** * Return "important" positions used in parsing non-nested HTML tags. * *
         *   
         *  ^    ^           ^ ^
         *  0    1           2 3
         * 
* * @param contents The original contents of the HTML file. * @param lower The lower-cased version of contents. * @param tagName The HTML tag-name to find. * @param index The index to start the search from. * @return Array of four interesting positions. */ private int[] getTagPositions(String contents, String lower, String tagName, int index) { // !!!! assumes that "<" is to the immediate left of the tag name int tagStart = lower.indexOf("<" + tagName, index); if (tagStart == -1) return null; // !!!! doesn't properly handle '>' inside a quoted string int tagEnd = lower.indexOf(">", tagStart); if (tagEnd == -1) return null; return new int[] { tagStart, tagStart + tagName.length() + 1, tagEnd, tagEnd + 1 }; } // getTagPositions() /** * Parse the attributes of an HTML tag. * * @param attrs A string containing HTML attributes. * @return Map of HTML attributes (name/value pairs). */ private Map parseAttrs(String attrs) { Map result = new HashMap<>(3); int startPos = 0; int[] positions; while ((positions = getAttrPositions(attrs, startPos)) != null) { String value = attrs.substring(positions[2], positions[3]); if ((value.indexOf("\"") == 0) && (value.lastIndexOf("\"") == value.length() - 1)) value = value.substring(1, value.length() - 1); result.put(attrs.substring(positions[0], positions[1]).toLowerCase(), value); startPos = positions[3]; } return result; } // parseAttrs() //----------member variables-------------------------------------------- String body; Map appletParams = new HashMap<>(1); Map appletAttrs; } // class HTMLFileContents //----------member variables---------------- -------------------------------- private String manual = "unset"; // or "novalue", "done", "yesno" private boolean reverseStatus = false; private boolean othervm = false; private int timeout = -1; private File policyFN = null; private String secureFN = null; private boolean overrideSysPolicy = false; private String htmlFN; private String clsName; private HTMLFileContents htmlFileContents; private static final Object appletLock = new Object(); } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/exec/BuildAction.java000066400000000000000000000307001461415321300301410ustar00rootroot00000000000000/* * Copyright (c) 1998, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.exec; import java.io.File; import java.io.PrintWriter; import java.nio.file.Path; import java.text.DateFormat; import java.util.ArrayList; import java.util.Date; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; import com.sun.javatest.Status; import com.sun.javatest.regtest.config.Locations; import com.sun.javatest.regtest.config.Locations.ClassLocn; import com.sun.javatest.regtest.config.Locations.LibLocn; import com.sun.javatest.regtest.config.ParseException; import com.sun.javatest.regtest.util.FileUtils; import static com.sun.javatest.regtest.RStatus.passed; /** * This class implements the "build" action as described by the JDK tag * specification. * * @see Action */ public class BuildAction extends Action { public static final String NAME = "build"; /** * {@inheritDoc} * @return "build" */ @Override public String getName() { return NAME; } /** * A method used by sibling classes to run both the init() and run() * method of BuildAction. * * @param opts The options for the action. * @param reason Indication of why this action was invoked. * @param args The arguments for the actions. * @param script The script. * @return The result of the action. * @throws TestRunException if an error occurs during the work * @see #init * @see #run */ public Status build(Map opts, List args, String reason, RegressionScript script) throws TestRunException { init(opts, args, reason, script); return run(); } // build() /** * This method does initial processing of the options and arguments for the * action. Processing is determined by the requirements of run(). * * Verify that the options are of length 0 and that there is at least one * argument. * * @param opts The options for the action. * @param args The arguments for the actions. * @param reason Indication of why this action was invoked. * @param script The script. * @exception ParseException If the options or arguments are not expected * for the action or are improperly formated. */ @Override public void init(Map opts, List args, String reason, RegressionScript script) throws ParseException { super.init(opts, args, reason, script); for (Map.Entry e: opts.entrySet()) { String optName = e.getKey(); String optValue = e.getValue(); if (optName.equals("implicit") && optValue.equals("none")) { implicitOpt = "-implicit:none"; continue; } throw new ParseException(BUILD_UNEXPECT_OPT); } if (args.isEmpty()) throw new ParseException(BUILD_NO_CLASSNAME); for (String currArg : args) { if (!BUILD_PTN.matcher(currArg).matches()) { throw new ParseException(BUILD_BAD_CLASSNAME + currArg); } } } // init() private static final String IGNORE_CASE = "(?i)"; private static final String OPT_MODULE = "([a-z_][.a-z0-9_$]*/)?"; private static final String PKG_CLASS = "(([a-z_][.a-z0-9_$]*)(\\.\\*|\\.package-info)?)"; private static final String PKG_CLASS_OR_OTHER = "(" + PKG_CLASS + "|\\*|module-info)"; static final Pattern BUILD_PTN = Pattern.compile(IGNORE_CASE + OPT_MODULE + PKG_CLASS_OR_OTHER); @Override public Set getSourceFiles() { Set files = new LinkedHashSet<>(); for (String arg: args) { // the arguments to build are classnames or package names with wildcards try { for (ClassLocn cl: script.locations.locateClasses(arg)) { files.add(cl.absSrcFile.toFile()); } } catch (Locations.Fault ignore) { } } return files; } @Override public Set getModules() { Set modules = new LinkedHashSet<>(); for (String arg: args) { int sep = arg.indexOf("/"); if (sep > 0) modules.add(arg.substring(0, sep)); } return modules; } /** * The method that does the work of the action. The necessary work for the * given action is defined by the tag specification. * * Each named class will be compiled if its corresponding class file doesn't * exist or is older than its source file. The class name is fully * qualified as necessary and the ".java" extension is added before * compilation. * * Build is allowed to search anywhere in the library-list. Compile is * allowed to search only in the directory containing the defining file of * the test. Thus, compile will always absolutify by adding the directory * path of the defining file to the passed filename. Build must pass an * absolute filename to handle files found in the library-list. * * @return The result of the action. * @throws TestRunException If an unexpected error occurs while running * the test. */ @Override public Status run() throws TestRunException { startAction(false); // step 1: see which files need compiling, and group them according // to the value of the library in which they appear, and hence // -d flag that will be required PrintWriter pw = section.getMessageWriter(); long now = System.currentTimeMillis(); Map> classLocnsToCompile = new LinkedHashMap<>(); for (String arg: args) { try { for (ClassLocn cl: script.locations.locateClasses(arg)) { long sfMillis = FileUtils.getLastModifiedTime(cl.absSrcFile).toMillis(); if (sfMillis > now) { pw.println(String.format(BUILD_FUTURE_SOURCE, cl.absSrcFile, DateFormat.getDateTimeInstance().format(new Date(sfMillis)))); pw.println(BUILD_FUTURE_SOURCE_2); } if (!cl.isUpToDate()) { List classLocnsForLib = classLocnsToCompile.get(cl.lib); if (classLocnsForLib == null) { classLocnsForLib = new ArrayList<>(); classLocnsToCompile.put(cl.lib, classLocnsForLib); } classLocnsForLib.add(cl); } } } catch (Locations.Fault e) { throw new TestRunException(e.getMessage()); } } // step 2: perform the compilations, if any Status status; if (classLocnsToCompile.isEmpty()) { status = passed(BUILD_UP_TO_DATE); } else { status = null; // ensure that all directories are created for any library classes for (Path dir: script.locations.absLibClsList(LibLocn.Kind.PACKAGE)) { FileUtils.createDirectories(dir); } // compile libraries first for (Map.Entry> e: classLocnsToCompile.entrySet()) { if (e.getKey().name != null) { Status s = compileLibrary(e.getKey(), e.getValue()); if (!s.isPassed()) { status = s; break; } } } // compile test code if (status == null) { for (Map.Entry> e: classLocnsToCompile.entrySet()) { if (e.getKey().name == null) { Status s = compileLibrary(e.getKey(), e.getValue()); if (!s.isPassed()) { status = s; break; } } } } if (status == null) status = passed(BUILD_SUCC); } endAction(status); return status; } // run() private Status compileLibrary(LibLocn libLocn, List classLocns) throws TestRunException { showClasses(libLocn, classLocns); switch (libLocn.kind) { case PACKAGE: return compileFiles(libLocn, false, null, getSrcFiles(classLocns)); case USER_MODULE: return compileFiles(libLocn, true, null, getSrcFiles(classLocns)); case SYS_MODULE: Map> filesForModule = new LinkedHashMap<>(); for (ClassLocn cl: classLocns) { List files = filesForModule.get(cl.optModule); if (files == null) { filesForModule.put(cl.optModule, files = new ArrayList<>()); } files.add(cl.absSrcFile.toFile()); } for (Map.Entry> e: filesForModule.entrySet()) { Status s = compileFiles(libLocn, false, e.getKey(), e.getValue()); if (!s.isPassed()) return s; } return passed(BUILD_SUCC); case PRECOMPILED_JAR: default: throw new AssertionError(); } } private Status compileFiles(LibLocn libLocn, boolean isMulti, String moduleName, List files) throws TestRunException { Map compOpts = new LinkedHashMap<>(); if (isMulti) { compOpts.put("modules", null); } if (moduleName != null) { compOpts.put("module", moduleName); } List compArgs = new ArrayList<>(); if (script.getCompileJDK().hasOldSymbolFile()) compArgs.add("-XDignore.symbol.file=true"); if (implicitOpt != null) compArgs.add(implicitOpt); for (File file: files) compArgs.add(file.getPath()); CompileAction ca = new CompileAction(); return ca.compile(libLocn, compOpts, compArgs, SREASON_FILE_TOO_OLD, script); } private List getSrcFiles(List classLocns) { List files = new ArrayList<>(); for (ClassLocn cl: classLocns) { files.add(cl.absSrcFile.toFile()); } return files; } private void showClasses(LibLocn lib, List toCompile) { PrintWriter pw = section.getMessageWriter(); if (lib.name == null) { pw.println("Test directory:"); } else { pw.println("Library " + lib.name + ":"); } String sep = " compile: "; for (ClassLocn cl: toCompile) { pw.print(sep); if (cl.optModule != null) { pw.print(cl.optModule); pw.print("/"); } pw.print(cl.className); sep = ", "; } pw.println(); } //----------member variables------------------------------------------------ private String implicitOpt; } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/exec/CleanAction.java000066400000000000000000000160661461415321300301350ustar00rootroot00000000000000/* * Copyright (c) 1998, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.exec; import java.io.File; import java.nio.file.Files; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import com.sun.javatest.Status; import com.sun.javatest.regtest.config.Locations; import com.sun.javatest.regtest.config.Locations.ClassLocn; import com.sun.javatest.regtest.config.ParseException; import javax.lang.model.SourceVersion; import static com.sun.javatest.regtest.RStatus.error; import static com.sun.javatest.regtest.RStatus.passed; /** * This class implements the "clean" action as described by the JDK tag * specification. * * @see Action */ public class CleanAction extends Action { public static final String NAME = "clean"; /** * {@inheritDoc} * @return "clean" */ @Override public String getName() { return NAME; } /** * This method does initial processing of the options and arguments for the * action. Processing is determined by the requirements of run(). * * Verify that the passed options and arguments are of length 0. * * @param opts The options for the action. * @param args The arguments for the actions. * @param reason Indication of why this action was invoked. * @param script The script. * @exception ParseException If the options or arguments are not expected * for the action or are improperly formatted. */ @Override public void init(Map opts, List args, String reason, RegressionScript script) throws ParseException { super.init(opts, args, reason, script); if (!opts.isEmpty()) throw new ParseException(CLEAN_UNEXPECT_OPT); if (args.isEmpty()) throw new ParseException(CLEAN_NO_CLASSNAME); for (String arg : args) { // allow "clean default package" marker if ("*".equals(arg)) continue; // allow qualified class name with optional "clean any package" pattern String name = arg.endsWith(".*") ? arg.substring(0, arg.length() - 2) : arg; if (SourceVersion.isName(name)) continue; // detected a syntactically invalid class name throw new ParseException(CLEAN_BAD_CLASSNAME + arg); } } // init() /** * The method that does the work of the action. The necessary work for the * given action is defined by the tag specification. * * Remove the class files for the named classes, if they exist. Limited * wildcard processing is supported. The class name is fully qualified as * necessary before deletion. * * @return The result of the action. * @exception TestRunException If an unexpected error occurs while running * the test. */ public Status run() throws TestRunException { // This doesn't complain if the specified file doesn't exist Status status = passed(CLEAN_SUCC); startAction(false); if (script.isCheck()) { status = passed(CHECK_PASS); } else { for (String arg : args) { // NOTE -- should probably clean library-compiled classes // as well. if (arg.equals("*")) // clean default package arg = ".*"; if (arg.endsWith(".*")) { // clean any package String path = arg.substring(0, arg.length() -2); path = path.replace('.', File.separatorChar); File dir = script.absTestClsDir().toFile(); if (!path.equals("")) dir = new File(dir, path); recorder.exec("for f in " + dir + "/*; do\n" + " if [ -f $f ]; then rm $f ; fi\n" + "done"); try { if (dir.isDirectory()) { File[] files = dir.listFiles(); if (files != null) { for (File f : files) { // don't complain about not being able to clean // subpackages if (!f.delete() && !f.isDirectory()) throw new TestRunException(CLEAN_RM_FAILED + f); } } } } catch (SecurityException e) { // shouldn't happen as JavaTestSecurityManager allows file ops throw new TestRunException(CLEAN_SECMGR_PROB + dir); } } else { // clean class file File victim = script.absTestClsDir().resolve( arg.replace('.', File.separatorChar) + ".class").toFile(); recorder.exec("rm -f " + victim); if (victim.exists() && !victim.delete()) return error(CLEAN_RM_FAILED + victim); } } } endAction(status); return status; } // run() @Override public Set getSourceFiles() { Set files = new LinkedHashSet<>(); for (String arg: args) { // the arguments to clean are class names or package names with wildcards try { for (ClassLocn cl: script.locations.locateClasses(arg)) { if (Files.exists(cl.absSrcFile)) files.add(cl.absSrcFile.toFile()); } } catch (Locations.Fault ignore) { } } return files; } //----------member variables------------------------------------------------ } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/exec/CompileAction.java000066400000000000000000001101651461415321300304760ustar00rootroot00000000000000/* * Copyright (c) 1998, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.exec; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.PrintStream; import java.io.PrintWriter; import java.io.StringReader; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; import com.sun.javatest.Status; import com.sun.javatest.regtest.TimeoutHandler; import com.sun.javatest.regtest.agent.AStatus; import com.sun.javatest.regtest.agent.CompileActionHelper; import com.sun.javatest.regtest.agent.JDK_Version; import com.sun.javatest.regtest.agent.SearchPath; import com.sun.javatest.regtest.config.ExecMode; import com.sun.javatest.regtest.config.JDK; import com.sun.javatest.regtest.config.JDKOpts; import com.sun.javatest.regtest.config.Locations; import com.sun.javatest.regtest.config.Locations.LibLocn; import com.sun.javatest.regtest.config.Modules; import com.sun.javatest.regtest.config.ParseException; import com.sun.javatest.regtest.exec.RegressionScript.PathKind; import com.sun.javatest.regtest.util.StringUtils; import static com.sun.javatest.regtest.RStatus.createStatus; import static com.sun.javatest.regtest.RStatus.error; import static com.sun.javatest.regtest.RStatus.failed; import static com.sun.javatest.regtest.RStatus.normalize; import static com.sun.javatest.regtest.RStatus.passed; /** * This class implements the "compile" action as described by the JDK tag * specification. It is also invoked implicitly as needed by the "build" * action. * * @see Action * @see com.sun.javatest.regtest.agent.MainActionHelper */ public class CompileAction extends Action { public static final String NAME = "compile"; /** * {@inheritDoc} * @return "compile" */ @Override public String getName() { return NAME; } /** * A method used by sibling classes to run both the init() and run() * method of CompileAction. * * @param libLocn details for where to place the compiled classes * @param opts The options for the action. * @param args The arguments for the actions. * @param reason Indication of why this action was invoked. * @param script The script. * @return The result of the action. * @throws TestRunException if an error occurs while executing this action * @see #init * @see #run */ Status compile(LibLocn libLocn, Map opts, List args, String reason, RegressionScript script) throws TestRunException { this.libLocn = libLocn; init(opts, args, reason, script); return run(); } // compile() /** * This method does initial processing of the options and arguments for the * action. Processing is determined by the requirements of run() and * getSourceFiles(). If run will be called, script.hasEnv() will be true. * If script.hasEnv() is false, there is no context available to determine * any class directories. * * Verify that the options are valid for the "compile" action. * * Verify that there is at least one argument. Find the class names to * compile (via presence of ".java") and modify to contain fully qualified * path. * * If one of the JVM options is "-classpath" or "-cp", add the test classes * and test sources directory to the provided path. * * @param opts The options for the action. * @param args The arguments for the actions. * @param reason Indication of why this action was invoked. * @param script The script. * @exception ParseException If the options or arguments are not expected * for the action or are improperly formated. */ @Override public void init(Map opts, List args, String reason, RegressionScript script) throws ParseException { super.init(opts, args, reason, script); if (reason.startsWith(SREASON_USER_SPECIFIED)) addDebugOpts = true; if (args.isEmpty()) throw new ParseException(COMPILE_NO_CLASSNAME); for (Map.Entry e: opts.entrySet()) { String optName = e.getKey(); String optValue = e.getValue(); switch (optName) { case "fail": reverseStatus = parseFail(optValue); break; case "timeout": timeout = parseTimeout(optValue); break; case "ref": ref = parseRef(optValue); break; case "process": process = true; break; case "module": module = parseModule(optValue); modules = Collections.singleton(module); break; case "modules": if (optValue != null) throw new ParseException(COMPILE_MODULES_UEXPECT + optValue); multiModule = true; modules = new LinkedHashSet<>(); break; default: throw new ParseException(COMPILE_BAD_OPT + optName); } } if (module != null && multiModule) { throw new ParseException("Bad combination of options: /module=" + module + ", /modules"); } if (module == null && !multiModule) modules = Collections.emptySet(); if (timeout < 0) timeout = script.getActionTimeout(-1); // add absolute path name to all the .java files create appropriate // class directories Locations locations = script.locations; if (libLocn == null) { destDir = multiModule ? locations.absTestModulesDir().toFile() : locations.absTestClsDir(module).toFile(); } else { destDir = ((module == null) ? libLocn.absClsDir : libLocn.absClsDir.resolve(module)).toFile(); } if (!script.isCheck()) mkdirs(destDir); boolean foundJavaFile = false; boolean foundAsmFile = false; for (int i = 0; i < args.size(); i++) { // note: in the following code, some args are overwritten in place String currArg = args.get(i); if (currArg.endsWith(".java")) { foundJavaFile = true; File sourceFile = new File(currArg.replace('/', File.separatorChar)); if (!sourceFile.isAbsolute()) { // User must have used @compile, so file must be // in the same directory as the defining file. if (multiModule) addModule(currArg); Path absSourceFile = locations.absTestSrcFile(module, sourceFile); if (!Files.exists(absSourceFile)) throw new ParseException(CANT_FIND_SRC + currArg); args.set(i, absSourceFile.toString()); } } else if (currArg.endsWith(".jasm") || currArg.endsWith("jcod")) { if (module != null) { throw new ParseException(COMPILE_OPT_DISALLOW); } foundAsmFile = true; File sourceFile = new File(currArg.replace('/', File.separatorChar)); if (!sourceFile.isAbsolute()) { // User must have used @compile, so file must be // in the same directory as the defining file. if (multiModule) addModule(currArg); Path absSourceFile = locations.absTestSrcFile(null, sourceFile); if (!Files.exists(absSourceFile)) throw new ParseException(CANT_FIND_SRC + currArg); args.set(i, absSourceFile.toString()); } } if (currArg.equals("-classpath") || currArg.equals("-cp") || currArg.equals("--class-path") || currArg.startsWith("--class-path=")) { if (module != null || multiModule) { throw new ParseException(COMPILE_OPT_DISALLOW); } classpathp = true; if (!currArg.startsWith("--class-path=")) { i++; } } else if (currArg.equals("-sourcepath") || currArg.equals("--source-path") || currArg.startsWith("--source-path=")) { if (module != null || multiModule) { throw new ParseException(COMPILE_OPT_DISALLOW); } sourcepathp = true; if (!currArg.startsWith("--source-path=")) { i++; } } else if (currArg.equals("-d")) { throw new ParseException(COMPILE_OPT_DISALLOW); } } if (!foundJavaFile && !process && !foundAsmFile) { throw new ParseException(COMPILE_NO_DOT_JAVA); } if (foundAsmFile) { if (sourcepathp || classpathp || process) { throw new ParseException(COMPILE_OPT_DISALLOW); } if (reverseStatus || ref != null) { throw new ParseException(COMPILE_OPT_DISALLOW); } } } // init() @Override public Set getSourceFiles() { Set files = new LinkedHashSet<>(); for (String currArg : args) { if (currArg.endsWith(".java") || currArg.endsWith(".jasm") || currArg.endsWith(".jcod")) { files.add(new File(currArg)); } } return files; } @Override public Set getModules() { return modules; } /** * The method that does the work of the action. The necessary work for the * given action is defined by the tag specification. * * Invoke the compiler on the given arguments which may possibly include * compiler options. Equivalent to "javac arg+". * * Each named class will be compiled if its corresponding class file doesn't * exist or is older than its source file. The class name is fully * qualified as necessary and the ".java" extension is added before * compilation. * * Build is allowed to search anywhere in the library-list. Compile is * allowed to search only in the directory containing the defining file of * the test. Thus, compile will always make files absolute by adding the * directory path of the defining file to the passed filename. * Build must pass an absolute filename to handle files found in the * library-list. * * @return The result of the action. * @throws TestRunException If an unexpected error occurs while executing * the action. */ @Override public Status run() throws TestRunException { startAction(true); List javacArgs = new ArrayList<>(); List jasmArgs = new ArrayList<>(); List jcodArgs = new ArrayList<>(); boolean runJavac = process; int insertPos = -1; boolean seenSourceOrRelease = false; boolean seenEnablePreview = false; for (String currArg : args) { if (currArg.endsWith(".java")) { if (!(new File(currArg)).exists()) throw new TestRunException(CANT_FIND_SRC + currArg); if (insertPos == -1) { insertPos = javacArgs.size(); } javacArgs.add(currArg); runJavac = true; } else if (currArg.endsWith(".jasm")) { jasmArgs.add(currArg); } else if (currArg.endsWith(".jcod")) { jcodArgs.add(currArg); } else { int eq = currArg.indexOf("="); switch (eq == -1 ? currArg : currArg.substring(0, eq)) { case "--enable-preview": seenEnablePreview = true; break; case "-source": case "--source": case "--release": if (insertPos == -1) { insertPos = javacArgs.size(); } seenSourceOrRelease= true; break; } javacArgs.add(currArg); } } if (runJavac && script.enablePreview() && !seenEnablePreview) { javacArgs.add(insertPos, "--enable-preview"); if (!seenSourceOrRelease) { int v = script.getTestJDKVersion().major; javacArgs.add(insertPos + 1, "--source=" + v); } } Status status; if (script.isCheck()) { status = passed(CHECK_PASS); } else { // run jasm and jcod first (if needed) in case the resulting class // files will be required when compiling the .java files. status = passed("Not yet run"); if (status.isPassed() && !jasmArgs.isEmpty()) status = jasm(jasmArgs); if (status.isPassed() && !jcodArgs.isEmpty()) status = jcod(jcodArgs); if (status.isPassed() && runJavac) { javacArgs = getJavacCommandArgs(javacArgs); for (String arg: javacArgs) { if (arg.startsWith("-J")) { othervmOverrideReasons.add("JVM options specified for compiler"); break; } } if (explicitAnnotationProcessingRequested(javacArgs) && !getExtraModuleConfigOptions(Modules.Phase.DYNAMIC).isEmpty()) { othervmOverrideReasons.add("additional runtime exports needed for annotation processing"); } switch (!othervmOverrideReasons.isEmpty() ? ExecMode.OTHERVM : script.getExecMode()) { case AGENTVM: showMode(ExecMode.AGENTVM); status = runAgentJVM(javacArgs); break; case OTHERVM: showMode(ExecMode.OTHERVM, othervmOverrideReasons); status = runOtherJVM(javacArgs); break; default: throw new AssertionError(); } } } endAction(status); return status; } // run() //----------internal methods------------------------------------------------ private Status jasm(List files) { return asmtools("jasm", files); } private Status jcod(List files) { return asmtools("jcoder", files); } private Status asmtools(String toolName, List files) { if (files.isEmpty()) return Status.passed(toolName + ": no files"); List toolArgs = new ArrayList<>(); toolArgs.add("-d"); toolArgs.add(destDir.getPath()); toolArgs.addAll(files); try { String toolClassName = "org.openjdk.asmtools." + toolName + ".Main"; recorder.asmtools(toolClassName, toolArgs); Class toolClass = Class.forName(toolClassName); Constructor constr = toolClass.getConstructor(PrintStream.class, String.class); ByteArrayOutputStream baos = new ByteArrayOutputStream(); PrintStream ps = new PrintStream(baos); try { Object tool = constr.newInstance(ps, toolName); Method m = toolClass.getMethod("compile", String[].class); Object r = m.invoke(tool, new Object[] { toolArgs.toArray(new String[0]) }); if (r instanceof Boolean) { boolean ok = (Boolean) r; return ok ? Status.passed(toolName + " OK") : Status.failed(toolName + " failed"); } else return Status.error("unexpected result from " + toolName + ": " + r.toString()); } finally { try (PrintWriter out = section.createOutput(toolName)) { out.write(baos.toString()); } } } catch (ClassNotFoundException e) { return Status.error("can't find " + toolName); } catch (ReflectiveOperationException t) { return Status.error("error invoking " + toolName + ": " + t); } } /** * Determine the arguments for the compilation. * Three different types of compilation are supported. *
    *
  • Compilation of classes in the unnamed module. * This is the default "classic" compilation. * The output directory should be a package-oriented directory. * Sources and classes for the unnamed module are put on the * sourcepath and classpath. *
  • Compilation of classes in a single named user module. * This mode is indicated by the option /module=module-name * where module-name is not the name of a system module. * The output directory should be the appropriate subdirectory * of a module-oriented directory. * The output directory should appear on the classpath. * Sources and classes for the unnamed module are not available. *
  • Compilation of classes to patch those in a system module. * This mode is indicated by the option /module=module-name * where module-name is the name of a system module. *
  • Compilation of classes in one or more named user modules. * This mode is indicated by the option /modules. * The output directory should be a module-oriented directory. * Sources and classes for the unnamed module are put on the * sourcepath and classpath. *
*/ private List getJavacCommandArgs(List args) throws TestRunException { Map compilePaths = script.getCompilePaths(libLocn, multiModule, module); JDKOpts javacArgs = new JDKOpts(); javacArgs.addAll(script.getTestCompilerOptions()); if (isModuleOptionsAllowed(args)) { javacArgs.addAll(getExtraModuleConfigOptions(Modules.Phase.STATIC)); } if (destDir != null) { javacArgs.add("-d"); javacArgs.add(destDir.toString()); } // modulesourcepath and sourcepath are mutually exclusive if (multiModule) { javacArgs.addPath("--module-source-path", compilePaths.get(PathKind.MODULESOURCEPATH)); } else if (module != null) { // Note: any additional patches for this module will be // automatically merged with this one. javacArgs.addAll("--patch-module", module + "=" + compilePaths.get(PathKind.SOURCEPATH)); } else { javacArgs.addPath("--source-path", compilePaths.get(PathKind.SOURCEPATH)); } // Need to refine what it means to put absTestClsDir unconditionally on the compilePath SearchPath cp = compilePaths.get(PathKind.CLASSPATH); javacArgs.addPath("--class-path", cp); javacArgs.addPath("--module-path", compilePaths.get(PathKind.MODULEPATH)); SearchPath pp = compilePaths.get(PathKind.PATCHPATH); javacArgs.addAllPatchModules(pp); // will merge as needed with any similar preceding options if (pp != null && !pp.isEmpty() && cp != null && !cp.isEmpty()) { // provide addReads from patch modules to unnamed module(s). for (String s: getModules(pp)) { javacArgs.add("--add-reads=" + s + "=ALL-UNNAMED"); } } Set userMods = getModules(compilePaths.get(PathKind.MODULEPATH)); if (!userMods.isEmpty()) { javacArgs.add("--add-modules"); javacArgs.add(StringUtils.join(userMods, ",")); } javacArgs.addAll(args); return javacArgs.toList(); } private boolean isModuleOptionsAllowed(List args) { Iterator iter = args.iterator(); while (iter.hasNext()) { String option = iter.next(); switch (option) { case "-source": case "-target": case "--release": if (iter.hasNext()) { JDK_Version v = JDK_Version.forName(iter.next()); return v != null && v.compareTo(JDK_Version.V9) >= 0; } break; default: if (option.startsWith("--release=")) { JDK_Version v = JDK_Version.forName( option.substring(option.indexOf("=") + 1)); return v != null && v.compareTo(JDK_Version.V9) >= 0; } break; } } return true; } private Status runOtherJVM(List javacArgs) throws TestRunException { Status status; // Set test.src and test.classes for the benefit of annotation processors Map javacProps = script.getTestProperties(); // CONSTRUCT THE COMMAND LINE Map env = script.getEnvVars(); Path javacCmd = script.getJavacProg(); JDKOpts javacVMOpts = new JDKOpts(); javacVMOpts.addAll(script.getTestVMOptions()); if (addDebugOpts && script.getCompileJDK().equals(script.getTestJDK())) javacVMOpts.addAll(script.getTestDebugOptions()); if (explicitAnnotationProcessingRequested(javacArgs)) { javacVMOpts.addAll(getExtraModuleConfigOptions(Modules.Phase.DYNAMIC)); } // WRITE ARGUMENT FILE List fullJavacArgs = javacArgs; if (javacArgs.size() >= 10) { File argFile = getArgFile(); try (BufferedWriter w = new BufferedWriter(new FileWriter(argFile))) { for (String arg: javacArgs) { if (arg.startsWith("-J")) { // remove -J for now; it will be added back later javacVMOpts.add(arg.substring(2)); } else { w.write(arg); w.newLine(); } } } catch (IOException e) { return error(COMPILE_CANT_WRITE_ARGS); } catch (SecurityException e) { // shouldn't happen since JavaTestSecurityManager allows file ops return error(COMPILE_SECMGR_FILEOPS); } javacArgs = List.of("@" + argFile); } List command = new ArrayList<>(); command.add(javacCmd.toString()); for (String opt: javacVMOpts.toList()) command.add("-J" + opt); for (Map.Entry e: javacProps.entrySet()) command.add("-J-D" + e.getKey() + "=" + e.getValue()); command.addAll(javacArgs); if (showMode) showMode("compile", ExecMode.OTHERVM, section); if (showCmd) showCmd("compile", command, section); new ModuleConfig("Boot Layer (javac runtime environment)") .setFromOpts(javacVMOpts) .write(configWriter); new ModuleConfig("javac compilation environment") .setFromOpts(fullJavacArgs) .write(configWriter); recorder.javac(env, javacCmd, javacVMOpts.toList(), javacProps, javacArgs); // PASS TO PROCESSCOMMAND PrintStringWriter stdOut = new PrintStringWriter(); PrintStringWriter stdErr = new PrintStringWriter(); ProcessCommand cmd = new ProcessCommand() { @Override protected Status getStatus(int exitCode, Status logStatus) { // logStatus is never used by javac, so ignore it JDK_Version v = script.getCompileJDKVersion(); AStatus aStatus = CompileActionHelper.getStatusForJavacExitCode(v, exitCode); return new Status(aStatus.getType(), aStatus.getReason()); } }; TimeoutHandler timeoutHandler = script.getTimeoutHandlerProvider().createHandler(this.getClass(), script, section); cmd.setExecDir(script.absTestScratchDir().toFile()) .setCommand(command) .setEnvironment(env) .setStreams(stdOut, stdErr) .setTimeout(timeout, TimeUnit.SECONDS) .setTimeoutHandler(timeoutHandler); status = normalize(cmd.exec()); try (PrintWriter sysOut = section.createOutput("System.out")) { sysOut.write(stdOut.getOutput()); } try (PrintWriter sysErr = section.createOutput("System.err")) { sysErr.write(stdErr.getOutput()); } // EVALUATE THE RESULTS status = checkReverse(status, reverseStatus); // COMPARE OUTPUT TO GOLDENFILE IF REQUIRED // tag-spec says that "standard error is redirected to standard out // so that /ref can be used." Simulate this by concatenating streams. if ((ref != null) && status.isPassed()) { String combined = stdOut.getOutput() + stdErr.getOutput(); status = checkGoldenFile(combined, status); } return status; } // runOtherJVM() private Status runAgentJVM(List javacArgs) throws TestRunException { // TAG-SPEC: "The source and class directories of a test are made // available to main and applet actions via the system properties // "test.src" and "test.classes", respectively" Map javacProps = script.getTestProperties(); if (showMode) showMode("compile", ExecMode.AGENTVM, section); if (showCmd) showCmd("compile", javacArgs, section); Path javacProg = script.getJavacProg(); List javacVMOpts = script.getTestVMOptions(); recorder.javac(script.getEnvVars(), javacProg, javacVMOpts, javacProps, javacArgs); Agent agent; try { JDK jdk = script.getCompileJDK(); SearchPath agentClasspath = new SearchPath(jdk.getJDKClassPath(), script.getJavaTestClassPath()); List vmOpts = addDebugOpts && jdk.equals(script.getTestJDK()) ? join(script.getTestVMOptions(), script.getTestDebugOptions()) : script.getTestVMOptions(); agent = script.getAgent(jdk, agentClasspath, vmOpts, null, null); section.getMessageWriter().println("Agent id: " + agent.getId()); new ModuleConfig("Boot Layer (javac runtime environment)") .setFromOpts(agent.vmOpts) .write(configWriter); } catch (Agent.Fault e) { return error(AGENTVM_CANT_GET_VM + ": " + e.getCause()); } TimeoutHandler timeoutHandler = script.getTimeoutHandlerProvider().createHandler(this.getClass(), script, section); Status status; try { new ModuleConfig("javac compilation environment") .setFromOpts(javacArgs) .write(configWriter); status = agent.doCompileAction( script.getTestResult().getTestName(), javacProps, javacArgs, timeout, timeoutHandler, section); } catch (Agent.Fault e) { if (e.getCause() instanceof IOException) status = error(String.format(AGENTVM_IO_EXCEPTION, e.getCause())); else status = error(String.format(AGENTVM_EXCEPTION, e.getCause())); } if (status.isError()) { script.closeAgent(agent); } // EVALUATE THE RESULTS status = checkReverse(status, reverseStatus); // COMPARE OUTPUT TO GOLDENFILE IF REQUIRED // tag-spec says that "standard error is redirected to standard out // so that /ref can be used." Simulate this by concatenating streams. if ((ref != null) && status.isPassed()) { String outString = getOutput(OutputHandler.OutputKind.DIRECT); String errString = getOutput(OutputHandler.OutputKind.DIRECT_LOG); String stdOutString = getOutput(OutputHandler.OutputKind.STDOUT); String stdErrString = getOutput(OutputHandler.OutputKind.STDERR); String combined = (outString + errString + stdOutString + stdErrString); status = checkGoldenFile(combined, status); } return status; } // runAgentJVM() private String getOutput(OutputHandler.OutputKind kind) { String s = section.getOutput(kind.name); return (s == null) ? "" : s; } // See JavaCompiler.explicitAnnotationProcessingRequested private boolean explicitAnnotationProcessingRequested(List javacArgs) { for (String arg: javacArgs) { if (arg.equals("-processor") || arg.equals("-processorpath") || arg.equals("-processormodulepath") || arg.equals("-proc:only") || arg.equals("-Xprint")) { return true; } } return false; } //----------internal methods------------------------------------------------ /** * This method parses the ref action option used by the compile * action. It verifies that the indicated reference file exists in the * directory containing the defining file of the test. * * @param value The proposed filename for the reference file. * @return A string indicating the name of the reference file for the * test. * @exception ParseException If the passed filename is null, the empty * string, or does not exist. */ private String parseRef(String value) throws ParseException { if ((value == null) || (value.equals(""))) throw new ParseException(COMPILE_NO_REF_NAME); File refFile = script.absTestSrcDir().resolve(value).toFile(); if (!refFile.exists()) throw new ParseException(COMPILE_CANT_FIND_REF + refFile); return value; } // parseRef() private Status checkReverse(Status status, boolean reverseStatus) { if (!status.isError()) { boolean ok = status.isPassed(); int st = status.getType(); String sr; if (ok && reverseStatus) { sr = COMPILE_PASS_UNEXPECT; st = Status.FAILED; } else if (ok && !reverseStatus) { sr = COMPILE_PASS; } else if (!ok && reverseStatus) { sr = COMPILE_FAIL_EXPECT; st = Status.PASSED; } else { /* !ok && !reverseStatus */ sr = COMPILE_FAIL; } if ((st == Status.FAILED) && ! (status.getReason() == null) && !status.getReason().equals(EXEC_PASS)) sr += ": " + status.getReason(); status = createStatus(st, sr); } return status; } /** * Compare output against a reference file. * @param status default result if no differences found * @param actual the text to be compared against the reference file * @return a status indicating the first difference, or the default status * if no differences found * @throws TestRunException if the reference file can't be found */ private Status checkGoldenFile(String actual, Status status) throws TestRunException { File refFile = script.absTestSrcDir().resolve(ref).toFile(); try (BufferedReader actualReader = new BufferedReader(new StringReader(actual)); BufferedReader refReader = new BufferedReader(new FileReader(refFile)) ) { int lineNum; if ((lineNum = compareGoldenFile(actualReader, refReader)) != 0) { return failed(COMPILE_GOLD_FAIL + ref + COMPILE_GOLD_LINE + lineNum); } return status; } catch (FileNotFoundException e) { throw new TestRunException(COMPILE_CANT_FIND_REF + refFile); } catch (IOException e) { throw new TestRunException(COMPILE_CANT_READ_REF + refFile); } } /** * Line by line comparison of compile output and a reference file. If no * differences are found, then 0 is returned. Otherwise, the line number * where differences are first detected is returned. * * @param actualReader the reader for the output actually found * @param refReader the reader for the reference (expected) content * @return the line number where differences were first detected, * or 0 if no differences were detected */ private int compareGoldenFile(BufferedReader actualReader, BufferedReader refReader) throws TestRunException { Pattern ignoreLinesPattern = script.getIgnoreRefLinesPattern(); try { int lineNum = 0; for ( ; ; ) { String s1 = actualReader.readLine(); if (ignoreLinesPattern != null) { while (s1 != null && ignoreLinesPattern.matcher(s1).matches()) { section.getMessageWriter().println("Ignoring line: " + s1); s1 = actualReader.readLine(); } } String s2 = refReader.readLine(); lineNum++; if ((s1 == null) && (s2 == null)) return 0; if ((s1 == null) || (s2 == null) || !s1.equals(s2)) { return lineNum; } } } catch (IOException e) { Path refFile = script.absTestSrcDir().resolve(ref); throw new TestRunException(COMPILE_GOLD_READ_PROB + refFile); } } // compareGoldenFile() private void addModule(String file) { int sep = file.indexOf('/'); if (sep > 0) modules.add(file.substring(0, sep)); } //----------member variables------------------------------------------------ private LibLocn libLocn; private File destDir; private boolean reverseStatus = false; private String ref = null; private int timeout = -1; private boolean classpathp = false; private boolean sourcepathp = false; private boolean process = false; private String module = null; private boolean multiModule = false; private Set modules; private boolean addDebugOpts = false; protected Set othervmOverrideReasons = new LinkedHashSet<>(); } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/exec/DefaultTimeoutHandler.java000066400000000000000000000064051461415321300322020ustar00rootroot00000000000000/* * Copyright (c) 2014, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.exec; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.nio.file.Files; import java.nio.file.Path; import com.sun.javatest.regtest.TimeoutHandler; /** * This is the default timeout handler. It will run jstack on the process that * has timed out. */ public class DefaultTimeoutHandler extends TimeoutHandler { public DefaultTimeoutHandler(PrintWriter log, File outputDir, Path testJdk) { super(log, outputDir, testJdk); } @Override protected void runActions(Process proc, long pid) throws InterruptedException { runJstack(pid); } /** * Run jstack on the specified pid. * @param pid Process Id */ private void runJstack(long pid) throws InterruptedException { try { log.println("Running jstack on process " + pid); Path jstack = findJstack(); if (jstack == null) { log.println("Warning: Could not find jstack in: " + testJdk.getAbsolutePath()); log.println("Will not dump jstack output."); return; } ProcessBuilder pb = new ProcessBuilder(jstack.toAbsolutePath().toString(), pid + ""); pb.redirectErrorStream(true); Process p = pb.start(); try (BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()))) { String line; while ((line = reader.readLine()) != null) { log.println(line); } p.waitFor(); } } catch (IOException ex) { ex.printStackTrace(log); } } private Path findJstack() { Path p = testJdk.toPath(); Path jstack = p.resolve("bin").resolve("jstack"); if (!Files.exists(jstack)) { jstack = p.resolve("bin").resolve("jstack.exe"); if (!Files.exists(jstack)) { return null; } } return jstack; } } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/exec/DriverAction.java000066400000000000000000000075641461415321300303510ustar00rootroot00000000000000/* * Copyright (c) 2014, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.exec; import java.util.ArrayList; import java.util.List; import java.util.Map; import com.sun.javatest.regtest.config.ParseException; /** * This class implements the "driver" action, which is a variation of "main". * * @see MainAction */ public class DriverAction extends MainAction { public static final String NAME = "driver"; /** * {@inheritDoc} * @return "driver" */ @Override public String getName() { return NAME; } /** * This method does initial processing of the options and arguments for the * action. Processing is determined by the requirements of run(). * * Verify arguments are not of length 0 and separate them into the options * to java, the classname, and the parameters to the named class. * * Verify that the options are valid for the "driver" action. * * @param opts The options for the action. * @param args The arguments for the actions. * @param reason Indication of why this action was invoked. * @param script The script. * @exception ParseException If the options or arguments are not expected * for the action or are improperly formated. */ @Override public void init(Map opts, List args, String reason, RegressionScript script) throws ParseException { if (args.isEmpty()) { throw new ParseException(DRIVER_NO_CLASSNAME); } else { String cn = args.get(0); if (cn.startsWith("-")) throw new ParseException(DRIVER_UNEXPECT_VMOPT); } for (Map.Entry e: opts.entrySet()) { String optName = e.getKey(); if (optName.equals("fail") || optName.equals("timeout")) continue; throw new ParseException(optName + " not supported"); } super.init(opts, args, reason, script); } // init() @Override List filterJavaOpts(List args) { List results = new ArrayList<>(); int i = 0, n = args.size(); while (i < n) { String arg = args.get(i); if (arg.startsWith("-D")) { results.add(arg); } else if (i < n - 1) { switch (arg) { case "--module-path": case "--add-modules": case "--add-exports": case "--add-opens": results.add(arg); results.add(args.get(++i)); } } ++i; } return results; } } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/exec/IgnoreAction.java000066400000000000000000000106351461415321300303320ustar00rootroot00000000000000/* * Copyright (c) 1998, 2017, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.exec; import java.util.List; import java.util.Map; import com.sun.javatest.Status; import com.sun.javatest.regtest.config.ParseException; import com.sun.javatest.regtest.util.StringUtils; import static com.sun.javatest.regtest.RStatus.error; import static com.sun.javatest.regtest.RStatus.passed; /** * This class implements the "ignore" action as described by the JDK tag * specification. * * @see Action */ public class IgnoreAction extends Action { public static final String NAME = "ignore"; /** * {@inheritDoc} * @return "ignore" */ @Override public String getName() { return NAME; } /** * This method does initial processing of the options and arguments for the * action. Processing is determined by the requirements of run(). * * Verify options are of length 0. * * @param opts The options for the action. * @param args The arguments for the actions. * @param reason Indication of why this action was invoked. * @param script The script. * @exception ParseException If the options or arguments are not expected * for the action or are improperly formated. */ @Override public void init(Map opts, List args, String reason, RegressionScript script) throws ParseException { super.init(opts, args, reason, script); if (!opts.isEmpty()) throw new ParseException(IGNORE_UNEXPECT_OPTS); } // init() /** * The method that does the work of the action. The necessary work for the * given action is defined by the tag specification. * * An automatic error which causes all subsquent actions to be ingored. All * arguments are joined as part of the returned error message. Equivalent * to "{@code echo *}". * * @return The result of the action. * @exception TestRunException If an unexpected error occurs while running * the test. */ public Status run() throws TestRunException { startAction(false); Status status; if (script.isCheck()) status = passed(CHECK_PASS); else switch (script.getIgnoreKind()) { case QUIET: throw new IllegalStateException(); case ERROR: recorder.exec("# @ignore: " + StringUtils.join(args, " ") + "\nexit 1"); if (args.isEmpty()) status = error(IGNORE_TEST_IGNORED); else status = error(IGNORE_TEST_IGNORED_C + StringUtils.join(args, " ")); break; case RUN: recorder.exec("# @ignore: " + StringUtils.join(args, " ") + " (suppressed)"); if (args.isEmpty()) status = passed(IGNORE_TEST_SUPPRESSED); else status = passed(IGNORE_TEST_SUPPRESSED_C + StringUtils.join(args, " ")); break; default: throw new IllegalArgumentException(); } endAction(status); return status; } // run() //----------member variables------------------------------------------------ } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/exec/JUnitAction.java000066400000000000000000000151311461415321300301340ustar00rootroot00000000000000/* * Copyright (c) 1998, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.exec; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import com.sun.javatest.Status; import com.sun.javatest.regtest.agent.JDK_Version; import com.sun.javatest.regtest.agent.JUnitRunner; import com.sun.javatest.regtest.config.Locations; import com.sun.javatest.regtest.config.ParseException; import com.sun.javatest.regtest.util.FileUtils; /** * This class implements the "junit" action, which is a variation of "main". * * @see MainAction */ public class JUnitAction extends MainAction { public static final String NAME = "junit"; /** * {@inheritDoc} * @return "junit" */ @Override public String getName() { return NAME; } /** * This method does initial processing of the options and arguments for the * action. Processing is determined by the requirements of run(). * * Verify arguments are not of length 0 and separate them into the options * to java, the classname, and the parameters to the named class. * * Verify that the options are valid for the "junit" action. * * @param opts The options for the action. * @param args The arguments for the actions. * @param reason Indication of why this action was invoked. * @param script The script. * @exception ParseException If the options or arguments are not expected * for the action or are improperly formatted. */ @Override public void init(Map opts, List args, String reason, RegressionScript script) throws ParseException { userSpecified = reason.startsWith(SREASON_USER_SPECIFIED); if (userSpecified && args.isEmpty()) throw new ParseException(JUNIT_NO_CLASSNAME); init(opts, args, reason, script, JUnitRunner.class, script.getTestResult().getTestName()); if (userSpecified && !getClassArgs().isEmpty()) throw new ParseException(JUNIT_BAD_MAIN_ARG); } // init() boolean userSpecified = false; // cache results? @Override protected Status build() throws TestRunException { if (userSpecified) { return super.build(); } else { JDK_Version v = script.getCompileJDKVersion(); Map buildOpts = new HashMap<>(); if (v.compareTo(JDK_Version.V1_6) >= 0) { buildOpts.put("implicit", "none"); } Locations locations = script.locations; Set buildArgs = new LinkedHashSet<>(script.getLibBuildArgs()); if (buildArgs.isEmpty()) { buildArgs.addAll(listModules(locations.absLibSrcList(Locations.LibLocn.Kind.SYS_MODULE))); buildArgs.addAll(listModules(locations.absLibSrcList(Locations.LibLocn.Kind.USER_MODULE))); buildArgs.addAll(listClasses(locations.absLibSrcList(Locations.LibLocn.Kind.PACKAGE))); } try { Path testSrcDir = locations.absTestSrcDir(); switch (locations.getDirKind(testSrcDir)) { case PACKAGE: buildArgs.addAll(listClasses(List.of(testSrcDir))); break; case SYS_MODULE: case USER_MODULE: buildArgs.addAll(listModules(List.of(testSrcDir))); break; } } catch (Locations.Fault e) { return Status.error(e.getMessage()); } BuildAction ba = new BuildAction(); return ba.build(buildOpts, new ArrayList<>(buildArgs), SREASON_ASSUMED_BUILD, script); } } private List listClasses(List roots) { List classes = new ArrayList<>(); for (Path root: roots) listClasses(root, null, classes); return classes; } private void listClasses(Path dir, String pkg, List classes) { // candidate for Files.walkFileTree for (Path f : FileUtils.listFiles(dir)) { String f_name = f.getFileName().toString(); if (Files.isDirectory(f)) { listClasses(f, pkg == null ? f_name : pkg + "." + f_name, classes); } else if (f_name.endsWith(".java")) { String c_name = f_name.substring(0, f_name.length() - 5); classes.add(pkg == null ? c_name : pkg + "." + c_name); } } } private Set listModules(List roots) { Set modules = new LinkedHashSet<>(); for (Path root: roots) { for (Path f : FileUtils.listFiles(root)) { if (Files.isDirectory(f)) { modules.add(f.getFileName() + "/*"); } } } return modules; } @Override public void endAction(Status s) { super.endAction(s); if (script.isCheck()) return; script.getJUnitSummaryReporter().add(script.getTestResult(), section); // String jtrPath = script.getTestResult().getWorkRelativePath(); // String tngPath = jtrPath.replaceAll("\\.jtr$", ".testng-results.xml"); // script.saveScratchFile(TESTNG_RESULTS_XML, Path.of(tngPath)); } } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/exec/Lock.java000066400000000000000000000075171461415321300266460ustar00rootroot00000000000000/* * Copyright (c) 2012, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.exec; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.channels.FileLock; import java.nio.file.Path; import java.util.Map; import java.util.WeakHashMap; import java.util.concurrent.locks.ReentrantLock; import com.sun.javatest.regtest.config.RegressionParameters; /** * A lock to protect access to shared resources between tests * */ public abstract class Lock { static Map locks = new WeakHashMap<>(); public static synchronized Lock get(RegressionParameters params) { Lock lock = locks.get(params); if (lock == null) { Path el = params.getExclusiveLock(); lock = (el == null) ? new SimpleLock() : new MultiVMLock(el.toFile()); locks.put(params, lock); } return lock; } public abstract void lock(); public abstract void unlock(); public void close() { } private static class SimpleLock extends Lock { ReentrantLock lock = new ReentrantLock(); @Override public void lock() { lock.lock(); } @Override public void unlock() { lock.unlock(); } } private static class MultiVMLock extends SimpleLock { private File file; private RandomAccessFile raf; private FileLock fileLock; MultiVMLock(File file) { try { this.file = file; while (!file.exists()) { file.createNewFile(); } raf = new RandomAccessFile(file, "rw"); } catch (IOException e) { throw new Error(e); } } @Override public void lock() { super.lock(); boolean acquired = false; try { fileLock = raf.getChannel().lock(); acquired = true; } catch (IOException e) { throw new Error(e); } finally { if (!acquired) super.unlock(); } } @Override public void unlock() { try { fileLock.release(); } catch (IOException e) { throw new Error(e); } finally { super.unlock(); } } @Override public void close() { try { raf.close(); // don't delete file -- it might still be in use by other JVMs // file.delete(); } catch (IOException e) { throw new Error(e); } } } } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/exec/MainAction.java000066400000000000000000000756451461415321300300070ustar00rootroot00000000000000/* * Copyright (c) 1998, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.exec; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; import java.util.EnumSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; import com.sun.javatest.Status; import com.sun.javatest.regtest.TimeoutHandler; import com.sun.javatest.regtest.agent.MainActionHelper.TestRunner; import com.sun.javatest.regtest.agent.MainWrapper; import com.sun.javatest.regtest.agent.SearchPath; import com.sun.javatest.regtest.config.ExecMode; import com.sun.javatest.regtest.config.JDK; import com.sun.javatest.regtest.config.JDKOpts; import com.sun.javatest.regtest.config.Locations.LibLocn; import com.sun.javatest.regtest.config.Modules; import com.sun.javatest.regtest.config.ParseException; import com.sun.javatest.regtest.exec.RegressionScript.PathKind; import com.sun.javatest.regtest.tool.Version; import com.sun.javatest.regtest.util.StringUtils; import static com.sun.javatest.regtest.RStatus.createStatus; import static com.sun.javatest.regtest.RStatus.error; import static com.sun.javatest.regtest.RStatus.failed; import static com.sun.javatest.regtest.RStatus.normalize; import static com.sun.javatest.regtest.RStatus.passed; /** * This class implements the "main" action as described by the JDK tag * specification. * * @see Action * @see com.sun.javatest.regtest.agent.MainActionHelper */ public class MainAction extends Action { public static final String NAME = "main"; /** * {@inheritDoc} * @return "main" */ @Override public String getName() { return NAME; } /** * This method does initial processing of the options and arguments for the * action. Processing is determined by the requirements of run(). * * Verify arguments are not of length 0 and separate them into the options * to java, the classname, and the parameters to the named class. * * Verify that the options are valid for the "main" action. * * @param opts The options for the action. * @param args The arguments for the actions. * @param reason Indication of why this action was invoked. * @param script The script. * @exception ParseException If the options or arguments are not expected * for the action or are improperly formated. */ @Override public void init(Map opts, List args, String reason, RegressionScript script) throws ParseException { init(opts, args, reason, script, null, (String[]) null); } /** * Local version of public init function. * Supports extra driverClass option, to interpose before main class. * @param driverClass actual class to invoke, with main class as first argument */ void init(Map opts, List args, String reason, RegressionScript script, Class driverClass, String... driverArgs) throws ParseException { super.init(opts, args, reason, script); if (args.isEmpty()) throw new ParseException(MAIN_NO_CLASSNAME); boolean othervm = false; for (Map.Entry e: opts.entrySet()) { String optName = e.getKey(); String optValue = e.getValue(); switch (optName) { case "fail": reverseStatus = parseFail(optValue); break; case "manual": manual = parseMainManual(optValue); break; case "timeout": timeout = parseTimeout(optValue); break; case "othervm": othervm = true; othervmOverrideReasons.add("/othervm specified"); break; case "native": nativeCode = true; break; case "bootclasspath": useBootClassPath = true; othervmOverrideReasons.add("/bootclasspath specified"); break; case "policy": overrideSysPolicy = true; policyFN = parsePolicy(optValue); break; case "java.security.policy": String name = optValue; if (optValue.startsWith("=")) { overrideSysPolicy = true; name = optValue.substring(1); } policyFN = parsePolicy(name); break; case "secure": secureCN = parseSecure(optValue); break; default: throw new ParseException(MAIN_BAD_OPT + optName); } } if (manual.equals("unset")) { if (timeout < 0) timeout = script.getActionTimeout(-1); } else { if (timeout >= 0) // can't have both timeout and manual throw new ParseException(PARSE_TIMEOUT_MANUAL); timeout = 0; } if (driverClass != null) { this.driverClass = driverClass; this.driverArgs = List.of(driverArgs); } if (script.useBootClassPath()) { useBootClassPath = true; othervmOverrideReasons.add("test or library uses bootclasspath"); } boolean seenEnablePreview = false; // separate the arguments into the options to java, the // classname and the parameters to the named class for (int i = 0; i < args.size(); i++) { String arg = args.get(i); if (testClassName == null) { if (arg.startsWith("-")) { if (arg.equals("--enable-preview")) { seenEnablePreview = true; } testJavaArgs.add(arg); if (JDKOpts.hasFollowingArg(arg)) { testJavaArgs.add(args.get(++i)); } } else { int sep = arg.indexOf("/"); if (sep == -1) { testModuleName = null; testClassName = arg; } else { testModuleName = arg.substring(0, sep); testClassName = arg.substring(sep + 1); } } } else { testClassArgs.add(arg); } } if (testClassName == null) throw new ParseException(MAIN_NO_CLASSNAME); if (!othervm) { // None of these need be fatal any more: we could just automatically // set othervm mode if any of the following conditions arise. if (testJavaArgs.size() > 0) throw new ParseException(testJavaArgs + MAIN_UNEXPECT_VMOPT); if (policyFN != null) throw new ParseException(PARSE_POLICY_OTHERVM); if (secureCN != null) throw new ParseException(PARSE_SECURE_OTHERVM); } if (script.enablePreview() && !seenEnablePreview) { testJavaArgs.add("--enable-preview"); if (!othervm) { // ideally, this should not force othervm mode, but just allow // the use of an agent with preview enabled othervmOverrideReasons.add("test requires --enable-preview"); } } if (!othervm) { for (Modules.Entry m : script.getModules()) { String name = m.moduleName; if (script.systemModules.contains(name) && !script.defaultModules.contains(name)) { othervmOverrideReasons.add("test requires non-default system module"); break; } } } if (!othervm && (this instanceof TestNGAction || this instanceof JUnitAction)) { Set testKinds = script.locations.getDirKinds(script.locations.absTestSrcDir()); boolean multiModule = testKinds.equals(EnumSet.of(LibLocn.Kind.USER_MODULE)); if (multiModule) { // agent won't be able to load driver class as agent's classes aren't // loaded by the CL which loaded these modules othervmOverrideReasons.add("test requires testng and/or junit as modules"); } } } // init() public List getJavaArgs() { return testJavaArgs; } public String getModuleName() { return testModuleName; } public String getClassName() { return testClassName; } public List getClassArgs() { return testClassArgs; } List filterJavaOpts(List args) { return args; } @Override public Set getSourceFiles() { Set files = new LinkedHashSet<>(); if (testClassName != null) { Map buildOpts = Collections.emptyMap(); List buildArgs = List.of(join(testModuleName, testClassName)); try { BuildAction ba = new BuildAction(); ba.init(buildOpts, buildArgs, SREASON_ASSUMED_BUILD, script); files.addAll(ba.getSourceFiles()); } catch (ParseException ignore) { } } if (policyFN != null) files.add(policyFN); return files; } @Override public Set getModules() { return (testModuleName == null) ? Collections.emptySet() : Collections.singleton(testModuleName); } /** * The method that does the work of the action. The necessary work for the * given action is defined by the tag specification. * * Invoke the main method of the specified class, passing any arguments * after the class name. A "main" action is considered to be finished when * the main method returns. * * A "main" action passes if the main method returns normally and does not * cause an exception to be thrown by the main or any subsidiary threads. * It fails otherwise. * * @return The result of the action. * @exception TestRunException If an unexpected error occurs while running * the test. */ @Override public Status run() throws TestRunException { if (script.usePatchModules()) othervmOverrideReasons.add("test or library overrides a system module"); Status status; if (!(status = build()).isPassed()) return status; if (nativeCode && script.getNativeDir() == null) return error(MAIN_NO_NATIVES); if (script.isCheck()) { startAction(true); status = passed(CHECK_PASS); endAction(status); } else { Lock lock = script.getLockIfRequired(); if (lock != null) lock.lock(); // Start action after the lock is taken to ensure correct "elapsed time". startAction(true); try { switch (!othervmOverrideReasons.isEmpty() ? ExecMode.OTHERVM : script.getExecMode()) { case AGENTVM: showMode(ExecMode.AGENTVM); status = runAgentJVM(); break; case OTHERVM: showMode(ExecMode.OTHERVM, othervmOverrideReasons); status = runOtherJVM(); break; default: throw new AssertionError(); } } finally { // End action before releasing the lock. endAction(status); if (lock != null) lock.unlock(); } } return status; } // run() //----------internal methods------------------------------------------------ protected Status build() throws TestRunException { // TAG-SPEC: "The named will be compiled on demand, just as // though an "@run build " action had been inserted before // this action." Map buildOpts = Collections.emptyMap(); List buildArgs = List.of(join(testModuleName, testClassName)); BuildAction ba = new BuildAction(); return ba.build(buildOpts, buildArgs, SREASON_ASSUMED_BUILD, script); } private Status runOtherJVM() throws TestRunException { // Arguments to wrapper: String runModuleName; String runModuleClassName; List runClassArgs; if (driverClass == null) { runModuleName = testModuleName; runModuleClassName = join(testModuleName, testClassName); runClassArgs = testClassArgs; } else { runModuleName = null; runModuleClassName = driverClass.getName(); runClassArgs = new ArrayList<>(); runClassArgs.addAll(driverArgs); runClassArgs.add(join(testModuleName, testClassName)); runClassArgs.addAll(testClassArgs); } // WRITE ARGUMENT FILE File argFile = getArgFile(); try (BufferedWriter w = new BufferedWriter(new FileWriter(argFile))) { w.write(runModuleClassName + "\0"); w.write(StringUtils.join(runClassArgs, " ") + "\0"); } catch (IOException e) { return error(MAIN_CANT_WRITE_ARGS); } // CONSTRUCT THE COMMAND LINE // TAG-SPEC: "The source and class directories of a test are made // available to main and applet actions via the system properties // "test.src" and "test.classes", respectively" Map env = new LinkedHashMap<>(); env.putAll(getEnvVars(nativeCode)); // some tests are inappropriately relying on the CLASSPATH environment // variable being set, so force the use here. final boolean useCLASSPATH = true; Set testKinds = script.locations.getDirKinds(script.locations.absTestSrcDir()); boolean multiModule = testKinds.equals(EnumSet.of(LibLocn.Kind.USER_MODULE)); Map paths = script.getExecutionPaths(multiModule, runModuleName, useBootClassPath, true); SearchPath cp = paths.get(PathKind.CLASSPATH); if (useCLASSPATH && (cp != null) && !cp.isEmpty()) { env.put("CLASSPATH", cp.toString()); } Path javaCmd = script.getJavaProg(); JDKOpts javaOpts = new JDKOpts(); if (!useCLASSPATH) { javaOpts.addPath("--class-path", cp); } SearchPath bcpa = paths.get(PathKind.BOOTCLASSPATH_APPEND); SearchPath pp = paths.get(PathKind.PATCHPATH); javaOpts.addPath("-Xbootclasspath/a:", bcpa); javaOpts.addAllPatchModules(pp); javaOpts.addPath("--module-path", paths.get(PathKind.MODULEPATH)); Set addMods = addMods(paths); if (!addMods.isEmpty()) { javaOpts.add("--add-modules"); javaOpts.add(StringUtils.join(addMods, ",")); } if (pp != null && !pp.isEmpty() && bcpa != null && !bcpa.isEmpty()) { // provide --add-reads from patch modules to unnamed module(s). for (String s: getModules(pp)) { javaOpts.add("--add-reads=" + s + "=ALL-UNNAMED"); } } if (driverClass != null && testModuleName != null && testClassName.contains(".")) { Module driverModule = driverClass.getModule(); String exportTarget = driverModule.isNamed() ? driverModule.getName() : "ALL-UNNAMED"; String testPackage = testClassName.substring(0, testClassName.lastIndexOf(".")); javaOpts.add("--add-exports=" + testModuleName + "/" + testPackage + "=" + exportTarget); } javaOpts.addAll(getExtraModuleConfigOptions(Modules.Phase.DYNAMIC)); javaOpts.addAll(script.getTestVMJavaOptions()); javaOpts.addAll(script.getTestDebugOptions()); Map javaProps = new LinkedHashMap<>(); javaProps.putAll(script.getTestProperties()); if (policyFN != null) { // add permission to read JTwork/classes by adding a grant entry File newPolicyFN = addGrantEntries(policyFN, argFile); javaProps.put("java.security.policy", (overrideSysPolicy ? "=" : "") + newPolicyFN); } if (secureCN != null) { javaProps.put("java.security.manager", secureCN); } else if (policyFN != null) { javaProps.put("java.security.manager", "default"); } if (script.getTestThreadFactory() != null) { javaProps.put(MainWrapper.TEST_THREAD_FACTORY, script.getTestThreadFactory()); } if (script.getTestThreadFactoryPath() != null) { javaProps.put(MainWrapper.TEST_THREAD_FACTORY_PATH, script.getTestThreadFactoryPath()); } // javaProps.put("java.security.debug", "all"); javaOpts.addAll(testJavaArgs); String className = MainWrapper.class.getName(); List classArgs = new ArrayList<>(); classArgs.add(argFile.getPath()); classArgs.addAll(runClassArgs); List command = new ArrayList<>(); command.add(javaCmd.toString()); for (Map.Entry e: javaProps.entrySet()) command.add("-D" + e.getKey() + "=" + e.getValue()); command.addAll(filterJavaOpts(javaOpts.toList())); command.add(className); command.addAll(classArgs); // PASS TO PROCESSCOMMAND Status status; try (PrintWriter sysOut = section.createOutput("System.out"); PrintWriter sysErr = section.createOutput("System.err")) { if (showMode) showMode(getName(), ExecMode.OTHERVM, section); if (showCmd) showCmd(getName(), command, section); new ModuleConfig("Boot Layer").setFromOpts(javaOpts).write(configWriter); recorder.java(env, javaCmd, javaProps, javaOpts.toList(), className, classArgs); // RUN THE MAIN WRAPPER CLASS ProcessCommand cmd = new ProcessCommand(); cmd.setExecDir(script.absTestScratchDir().toFile()); // Set the exit codes and their associated strings. Note that we // require the use of a non-zero exit code for a passed test so // that we have a chance of detecting whether the test itself has // illegally called System.exit(0). cmd.setStatusForExit(Status.exitCodes[Status.PASSED], passed(EXEC_PASS)); cmd.setStatusForExit(Status.exitCodes[Status.FAILED], failed(EXEC_FAIL)); cmd.setDefaultStatus(failed(UNEXPECT_SYS_EXIT)); TimeoutHandler timeoutHandler = script.getTimeoutHandlerProvider().createHandler(this.getClass(), script, section); cmd.setCommand(command) .setEnvironment(env) .setStreams(sysOut, sysErr) .setTimeout(timeout, TimeUnit.SECONDS) .setTimeoutHandler(timeoutHandler); status = normalize(cmd.exec()); } // EVALUATE THE RESULTS status = checkReverse(status, reverseStatus); return status; } // runOtherJVM() private Set addMods(Map paths) { Set addMods = new LinkedHashSet<>(); if (testModuleName != null) addMods.add(testModuleName); addMods.addAll(getModules(paths.get(PathKind.MODULEPATH))); return addMods; } private Status runAgentJVM() throws TestRunException { String runModuleName; String runMainClass; List runMainArgs; if (driverClass == null) { runModuleName = testModuleName; runMainClass = testClassName; runMainArgs = testClassArgs; } else { runModuleName = null; runMainClass = driverClass.getName(); runMainArgs = new ArrayList<>(); runMainArgs.addAll(driverArgs); runMainArgs.add(testClassName); runMainArgs.addAll(testClassArgs); } Set testKinds = script.locations.getDirKinds(script.locations.absTestSrcDir()); boolean multiModule = testKinds.equals(EnumSet.of(LibLocn.Kind.USER_MODULE)); Map paths = script.getExecutionPaths(multiModule, runModuleName, useBootClassPath, true); JDK jdk = script.getTestJDK(); List stdLibs = new SearchPath() .append(script.getJavaTestClassPath()) .append(jdk.getJDKClassPath()) .append(script.getJUnitPath()) .append(script.getTestNGPath()) .asList(); Version v = script.getRequiredVersion(); // In the following, using the preferred behavior reduces the number of kinds of agents, // and so increases the reuse of agents, but some tests inadvertently rely on the old // behavior. Therefore, the new preferred behavior is opt-in for test suites that // require version 5.1 b01 or better. SearchPath classpath = paths.get(PathKind.CLASSPATH); SearchPath agentClasspath = (v.version == null) || (v.compareTo(new Version("5.1 b01")) >= 0) ? new SearchPath().append(stdLibs) // preferred behavior : new SearchPath(classpath).retainAll(stdLibs); // old behavior SearchPath runClasspath = new SearchPath(classpath).removeAll(stdLibs); SearchPath runModulePath = paths.get(PathKind.MODULEPATH); if (showMode) showMode(getName(), ExecMode.AGENTVM, section); // TAG-SPEC: "The source and class directories of a test are made // available to main and applet actions via the system properties // "test.src" and "test.classes", respectively" Map javaProps = script.getTestProperties(); Path javaProg = script.getJavaProg(); List javaArgs = new ArrayList<>(); javaArgs.add("-classpath"); javaArgs.add(classpath.toString()); if (runModulePath != null) { javaArgs.add("--module-path"); javaArgs.add(runModulePath.toString()); } Set runAddMods = addMods(paths); if (!runAddMods.isEmpty()) { javaArgs.add("--add-modules"); javaArgs.add(StringUtils.join(runAddMods, ",")); } recorder.java(script.getEnvVars(), javaProg, javaProps, javaArgs, runMainClass, runMainArgs); Agent agent; try { String factory = script.getTestThreadFactory() == null ? null : script.getTestThreadFactory(); agent = script.getAgent(jdk, agentClasspath, filterJavaOpts(join(script.getTestVMJavaOptions(), script.getTestDebugOptions())), factory, script.getTestThreadFactoryPath()); section.getMessageWriter().println("Agent id: " + agent.getId()); new ModuleConfig("Boot Layer").setFromOpts(agent.vmOpts).write(configWriter); } catch (Agent.Fault e) { return error(AGENTVM_CANT_GET_VM + ": " + e.getCause()); } TimeoutHandler timeoutHandler = script.getTimeoutHandlerProvider().createHandler(this.getClass(), script, section); Status status; try { Set runAddExports = new LinkedHashSet<>(); Set runAddOpens = new LinkedHashSet<>(); if (jdk.hasModules()) { for (Modules.Entry e : script.getModules()) { if (e.packageName != null) { if (e.addExports) { runAddExports.add(e.moduleName + "/" + e.packageName); } if (e.addOpens) { runAddOpens.add(e.moduleName + "/" + e.packageName); } } } } if (!runAddExports.isEmpty()) { StringBuilder sb = null; for (String s : runAddExports) { if (s.contains("/")) { if (sb == null) { sb = new StringBuilder(); sb.append("Additional exports to unnamed modules from @modules: "); } else { sb.append(" "); } sb.append(s); } } if (sb != null) { section.getMessageWriter().println(sb); } } if (!runAddOpens.isEmpty()) { StringBuilder sb = null; for (String s : runAddOpens) { if (s.contains("/")) { if (sb == null) { sb = new StringBuilder(); sb.append("Additional opens to unnamed modules from @modules: "); } else { sb.append(" "); } sb.append(s); } } if (sb != null) { section.getMessageWriter().println(sb); } } new ModuleConfig("Test Layer") .setAddExportsToUnnamed(runAddExports) .setAddOpensToUnnamed(runAddOpens) .setClassPath(runClasspath) .setModulePath(runModulePath) .write(configWriter); // This calls through to MainActionHelper.runClass status = agent.doMainAction( script.getTestResult().getTestName(), javaProps, runAddExports, runAddOpens, runAddMods, runClasspath, runModulePath != null ? runModulePath : new SearchPath(), runMainClass, runMainArgs, timeout, timeoutHandler, section); } catch (Agent.Fault e) { if (e.getCause() instanceof IOException) status = error(String.format(AGENTVM_IO_EXCEPTION, e.getCause())); else status = error(String.format(AGENTVM_EXCEPTION, e.getCause())); } if (status.isError()) { script.closeAgent(agent); } // EVALUATE THE RESULTS status = checkReverse(status, reverseStatus); return status; } // runAgentJVM() //----------utility methods------------------------------------------------- private String parseMainManual(String value) throws ParseException { if (value != null) throw new ParseException(MAIN_MANUAL_NO_VAL + value); else value = "novalue"; return value; } // parseMainManual() private Status checkReverse(Status status, boolean reverseStatus) { // The standard rule is that /fail will invert Passed and Failed results // but will leave Error results alone. But, for historical reasons // perpetuated by the Basic test program, a test calling System.exit // is reported with a Failed result, whereas Error would really be // more appropriate. Therefore, we take care not to invert the // status if System.exit was called to exit the test. if (!status.isError() && !status.getReason().startsWith(UNEXPECT_SYS_EXIT)) { boolean ok = status.isPassed(); int st = status.getType(); String sr; if (ok && reverseStatus) { sr = EXEC_PASS_UNEXPECT; st = Status.FAILED; } else if (ok && !reverseStatus) { if (status.getReason().isEmpty()) { sr = EXEC_PASS; } else { sr = status.getReason(); } } else if (!ok && reverseStatus) { sr = EXEC_FAIL_EXPECT; st = Status.PASSED; } else { /* !ok && !reverseStatus */ sr = EXEC_FAIL; } if ((st == Status.FAILED) && ! (status.getReason() == null) && !status.getReason().equals(EXEC_PASS)) sr += ": " + status.getReason(); status = createStatus(st, sr); } return status; } private String join(String moduleName, String className) { return (moduleName == null) ? className : moduleName + '/' + className; } //----------member variables------------------------------------------------ private final List testJavaArgs = new ArrayList<>(); private final List testClassArgs = new ArrayList<>(); private Class driverClass = null; private List driverArgs = null; private String testModuleName = null; private String testClassName = null; private File policyFN = null; private String secureCN = null; private boolean overrideSysPolicy = false; protected boolean reverseStatus = false; protected boolean useBootClassPath = false; protected Set othervmOverrideReasons = new LinkedHashSet<>(); protected boolean nativeCode = false; private int timeout = -1; private String manual = "unset"; // or "novalue" } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/exec/ModuleConfig.java000066400000000000000000000260221461415321300303210ustar00rootroot00000000000000/* * Copyright (c) 2016, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.exec; import java.io.PrintWriter; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import com.sun.javatest.regtest.agent.SearchPath; import com.sun.javatest.regtest.config.JDKOpts; import com.sun.javatest.regtest.util.StringUtils; import static com.sun.javatest.regtest.util.StringUtils.afterPart; import static com.sun.javatest.regtest.util.StringUtils.beforePart; import static com.sun.javatest.regtest.util.StringUtils.split; import static com.sun.javatest.regtest.util.StringUtils.join; /** * Reports details on module configurations. * The configuration can include any of the following information: * add mods, limit mods, add exports, add reads, module path, class path, * boot class path (append), patch (old style), patch. */ public class ModuleConfig { private final String title; private List addMods; private List limitMods; private Map> addExports; private Map> addOpens; private Map> addReads; private SearchPath modulePath; private SearchPath classPath; private SearchPath sourcePath; private SearchPath bootClassPathAppend; private Map patch; ModuleConfig(String title) { this.title = title; } ModuleConfig setFromOpts(JDKOpts opts) { setFromOpts(opts.toList()); return this; } ModuleConfig setFromOpts(List opts) { JDKOpts.OptionHandler h = new JDKOpts.OptionHandler() { @Override protected void handleOption(JDKOpts.Option option, String opt, String arg) { switch (option) { case ADD_EXPORTS: setAddExports(beforePart(arg, '='), split(afterPart(arg, '='), ',')); break; case ADD_MODULES: setAddModules(split(arg, ',')); break; case ADD_EXPORTS_PRIVATE: case ADD_OPENS: setAddOpens(beforePart(arg, '='), split(afterPart(arg, '='), ',')); break; case ADD_READS: setAddReads(beforePart(arg, '='), split(afterPart(arg, '='), ',')); break; case CLASS_PATH: setClassPath(new SearchPath(arg)); break; case SOURCE_PATH: setSourcePath(new SearchPath(arg)); break; case LIMIT_MODULES: setLimitModules(split(arg, ',')); break; case MODULE_PATH: setModulePath(new SearchPath(arg)); break; case PATCH_MODULE: setPatchPath(beforePart(arg, '='), new SearchPath(afterPart(arg, '='))); break; } } @Override protected void handleUnknown(String opt) { } }; h.handleOptions(opts); return this; } ModuleConfig setAddModules(List mods) { addMods = mods; return this; } ModuleConfig setLimitModules(List mods) { limitMods = mods; return this; } ModuleConfig setAddExportsToUnnamed(Set modules) { for (String module: modules) { if (module.contains("/")) { setAddExports(module, Collections.singletonList("ALL-UNNAMED")); } } return this; } ModuleConfig setAddOpensToUnnamed(Set modules) { for (String module: modules) { if (module.contains("/")) { setAddOpens(module, Collections.singletonList("ALL-UNNAMED")); } } return this; } ModuleConfig setAddExports(String modulePackage, List targetModules) { if (addExports == null) addExports = new TreeMap<>(); addExports.put(modulePackage, targetModules); return this; } ModuleConfig setAddOpens(String modulePackage, List targetModules) { if (addOpens == null) addOpens = new TreeMap<>(); addOpens.put(modulePackage, targetModules); return this; } ModuleConfig setAddReads(String module, List targetModules) { if (addReads == null) addReads = new TreeMap<>(); addReads.put(module, targetModules); return this; } ModuleConfig setBootClassPathAppend(SearchPath bootClassPathAppend) { this.bootClassPathAppend = bootClassPathAppend; return this; } ModuleConfig setClassPath(SearchPath classPath) { this.classPath = classPath; return this; } ModuleConfig setSourcePath(SearchPath sourcePath) { this.sourcePath = sourcePath; return this; } ModuleConfig setModulePath(SearchPath modulePath) { this.modulePath = modulePath; return this; } ModuleConfig setPatchPath(String module, SearchPath patchPath) { if (patch == null) patch = new TreeMap<>(); patch.put(module, patchPath); return this; } void write(PrintWriter pw) { Table table = new Table(); if (addMods != null && !addMods.isEmpty()) { table.addRow("add modules:", StringUtils.join(addMods, " ")); } if (limitMods != null && !limitMods.isEmpty()) { table.addRow("limit modules:", StringUtils.join(limitMods, " ")); } if (addExports != null && !addExports.isEmpty()) { String label = "add exports:"; for (Map.Entry> e: addExports.entrySet()) { table.addRow(label, e.getKey(), join(e.getValue(), " ")); label = ""; } } if (addOpens != null && !addOpens.isEmpty()) { String label = "add opens:"; for (Map.Entry> e: addOpens.entrySet()) { table.addRow(label, e.getKey(), join(e.getValue(), " ")); label = ""; } } if (addReads != null && !addReads.isEmpty()) { String label = "add reads:"; for (Map.Entry> e: addReads.entrySet()) { table.addRow(label, e.getKey(), join(e.getValue(), " ")); label = ""; } } if (modulePath != null) { String label = "module path:"; for (Path file: modulePath.asList()) { table.addRow(label, file.toString()); label = ""; } } if (sourcePath != null) { String label = "source path:"; for (Path file: sourcePath.asList()) { table.addRow(label, file.toString()); label = ""; } } if (classPath != null) { String label = "class path:"; for (Path file: classPath.asList()) { table.addRow(label, file.toString()); label = ""; } } if (bootClassPathAppend != null) { String label = "boot class path (append):"; for (Path file: bootClassPathAppend.asList()) { table.addRow(label, file.toString()); label = ""; } } if (patch != null) { String label = "patch:"; for (Map.Entry e: patch.entrySet()) { String module = e.getKey(); for (Path file: e.getValue().asList()) { table.addRow(label, module, file.toString()); label = ""; module = ""; } } } if (table.rows.isEmpty()) return; pw.println(title); table.write(pw, 2); pw.println(); } private static class Table { List> rows = new ArrayList<>(); void addRow(String... items) { rows.add(List.of(items)); } void write(PrintWriter pw, int indent) { int maxCols = 0; for (List row : rows) { maxCols = Math.max(maxCols, row.size()); } int[] widths = new int[maxCols]; for (List row : rows) { int col = 0; for (String item: row) { // Exclude the last non-empty column of any row from the width calculation // so that it can flow into other columns present in other rows. // This helps prevent filenames (always the last entry in a row) // from bloating column widths. if (col < row.size() - 1) { widths[col] = Math.max(widths[col], item.length()); } col++; } } for (List row : rows) { space(pw, indent); int col = 0; for (String item: row) { if (item == null) { space(pw, widths[col]); } else { pw.write(item); space(pw, widths[col] - item.length()); } if (widths[col] > 0) { pw.write(" "); } col++; } pw.println(); } } private void space(PrintWriter pw, int spaces) { for (int i = 0; i < spaces; i++) pw.print(" "); } } } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/exec/ProcessCommand.java000066400000000000000000000365631461415321300306760ustar00rootroot00000000000000/* * Copyright (c) 2014, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.exec; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import com.sun.javatest.Status; import com.sun.javatest.regtest.TimeoutHandler; import com.sun.javatest.regtest.agent.Alarm; import com.sun.javatest.regtest.util.ProcessUtils; import com.sun.javatest.regtest.util.StreamCopier; /** * A helper class to execute an arbitrary OS command. **/ public class ProcessCommand { /** * Set a status to be returned for a specific exit code, overwriting any * previous setting for this exit code. If the default status has not yet * been initialized, it is set to Status.error("unrecognized exit code"). * * @param exitCode The process exit code for which to assign a status. * @param status The status to associate with the exit code. * @return a reference to this object */ public ProcessCommand setStatusForExit(int exitCode, Status status) { if (statusTable == null) { statusTable = new HashMap<>(); if (defaultStatus == null) { defaultStatus = Status.error("unrecognized exit code"); } } statusTable.put(exitCode, status); return this; } /** * Set the default status to be returned for all exit codes. * This will not affect any values for specific exit codes that * may have been set with setStatusForExit. If this method is * not called, the default value will be Status.failed (for * backwards compatibility) unless setStatusForExit has been * called, which sets the default value to Status.error. * * @param status The default status to use when a specific status * has not been set for a particular process exit code. * @return a reference to this object */ public ProcessCommand setDefaultStatus(Status status) { if (statusTable == null) { statusTable = new HashMap<>(); } defaultStatus = status; return this; } /** * Set the directory in which to execute the process. * Use null to indicate the default directory. * @param dir the directory in which to execute the process. * @return a reference to this object * @see #getExecDir */ public ProcessCommand setExecDir(File dir) { execDir = dir; return this; } /** * Get the directory in which to execute the process, * or null if none set. * @return the directory in which to execute the process. * @see #setExecDir */ public File getExecDir() { return execDir; } /** * Sets the command to be executed. * @param cmd The command to be executed * @return a reference to this object */ public ProcessCommand setCommand(List cmd) { this.cmd = cmd; return this; } /** * Gets the command to be executed. * @return the command to be executed */ public List getCommand() { return cmd; } /** * Sets the environment for the command. * @param env The environment to be passed to the command * @return a reference to this object */ public ProcessCommand setEnvironment(Map env) { this.env = env; return this; } /** * Gets the environment used for the command. * @return the environment */ public Map getEnvironment() { return env; } /** * Set the streams for logging normal and error output. * @param out the stream used for normal output * @param err the stream uses for error output * @return a reference to this object */ public ProcessCommand setStreams(PrintWriter out, PrintWriter err) { if (out == null) { throw new IllegalArgumentException("Output stream is required"); } if (err == null) { throw new IllegalArgumentException("Error stream is required"); } this.out = out; this.err = err; return this; } /** * Get the stream for logging normal output. * @return the stream */ public PrintWriter getOutStream() { return out; } /** * Get the stream for logging error output. * @return the stream */ public PrintWriter getErrorStream() { return err; } /** * Set the timeout to wait for the launched process. * @param timeout the timeout * @param unit the unit of the timeout value * @return a reference to this object */ public ProcessCommand setTimeout(long timeout, TimeUnit unit) { this.timeout = TimeUnit.MILLISECONDS.convert(timeout, unit); return this; } /** * Get the timeout to wait for the launched process. * @return the timeout (in milliseconds) */ public long getTimeout() { return timeout; } /** * Handler to call in the case of a timeout. * @param timeoutHandler the handler * @return a reference to this object */ public ProcessCommand setTimeoutHandler(TimeoutHandler timeoutHandler) { this.timeoutHandler = timeoutHandler; return this; } /** * Get the timeout handler. * @return the timeout handler */ public TimeoutHandler getTimeoutHandler() { return timeoutHandler; } /** * Execute the command. * @return The result of the method is obtained by calling * getStatus after the command completes. * @throws NullPointerException if an element of the command list is null * @throws IndexOutOfBoundsException if the command is an empty list (has size 0) * @see #getStatus */ public Status exec() { if (out == null) { throw new IllegalArgumentException("Output stream is required"); } if (err == null) { throw new IllegalArgumentException("Error stream is required"); } try { ProcessBuilder pb = new ProcessBuilder(cmd); pb.directory(execDir); if (env != null) { pb.environment().clear(); pb.environment().putAll(env); } final Process process = pb.start(); InputStream processIn = process.getInputStream(); InputStream processErr = process.getErrorStream(); long start = System.currentTimeMillis(); Alarm alarm = Alarm.NONE; final CountDownLatch timeoutHandlerDone = new CountDownLatch(1); if (timeout > 0) { final Thread victim = Thread.currentThread(); alarm = Alarm.schedule(timeout, TimeUnit.MILLISECONDS, out, new Runnable() { public void run() { invokeTimeoutHandler(timeoutHandler, timeoutHandlerDone, process, victim); } }); } OutputStream processOut = process.getOutputStream(); // input stream to process if (processOut != null) { processOut.close(); } try { StatusScanner statusScanner = new StatusScanner(); StreamCopier outCopier = new StreamCopier(processIn, out); StreamCopier errCopier = new StreamCopier(processErr, err, statusScanner); outCopier.start(); errCopier.start(); outCopier.join(); errCopier.join(); int exitCode = process.waitFor(); // if the timeout hasn't fired, cancel it as quickly as possible alarm.cancel(); return getStatus(exitCode, statusScanner.exitStatus()); } catch (InterruptedException e) { alarm.cancel(); return Status.error("Program `" + cmd.get(0) + "' interrupted"); } finally { processIn.close(); processErr.close(); alarm.cancel(); // if the timeout has fired - wait for the timeout handler to finish if (alarm.didFire()) { boolean done = waitForTimeoutHandler(timeoutHandlerDone, timeoutHandler); String msg = "Program `" + cmd.get(0) + "' timed out"; if (!done) { msg += ": timeout handler did not complete within its own timeout."; } long end = System.currentTimeMillis(); msg += " (timeout set to " + timeout + "ms, elapsed time including timeout handling was " + (end - start) + "ms)."; return Status.error(msg); } } } catch (IOException e) { String msg = "Error invoking program `" + cmd.get(0) + "': " + e; return Status.error(msg); } } private void invokeTimeoutHandler(final TimeoutHandler timeoutHandler, final CountDownLatch timeoutHandlerDone, final Process process, final Thread victim) { // Invocations from an Alarm call should be quick so that the Alarm thread pool // is not consumed. Because of that, we launch the timeout handling in a // separate Thread here. Timeout handling can take a very long time. Thread timeoutHandlerThread = new Thread() { @Override public void run() { if (timeoutHandler != null) { timeoutHandler.handleTimeout(process); } ProcessUtils.destroyForcibly(process); timeoutHandlerDone.countDown(); // JDK 1.8 introduces a Process.waitFor(timeout) method which could // be used here. We need run on 1.5 so using interrupt() instead. victim.interrupt(); } }; timeoutHandlerThread.setName("Timeout Handler for " + cmd.get(0)); timeoutHandlerThread.start(); } private boolean waitForTimeoutHandler(CountDownLatch timeoutHandlerDone, TimeoutHandler timeoutHandler) { boolean done = true; while(timeoutHandlerDone.getCount() != 0) { try { if (timeoutHandler.getTimeout() <= 0) { timeoutHandlerDone.await(); } else { done = timeoutHandlerDone.await(timeoutHandler.getTimeout() + 10, TimeUnit.SECONDS); } } catch (InterruptedException ex) { // ignore } } return done; } private static class StatusScanner implements StreamCopier.LineScanner { private String lastStatusLine; public void scan(String line) { if (line.startsWith(Status.EXIT_PREFIX)) { line = Status.decode(line); lastStatusLine = line; } } /** * Return the status information from the child process if it returned * any on the log stream, otherwise return null. */ public Status exitStatus() { if (lastStatusLine == null) { return null; } else { return Status.parse(lastStatusLine.substring(Status.EXIT_PREFIX.length())); } } } /** * Generate a status for the command, based upon the command's exit code * and a status that may have been passed from the command by using * status.exit(). * * @param exitCode The exit code from the command that was executed. * @param logStatus If the command that was executed was a test program * and exited by calling status.exit(), * then logStatus will be set to `status'. Otherwise, * it will be null. The value of the status is passed * from the command by writing it as the last line to * stdout before exiting the process. If it is not * received as the last line, the value will be lost. * @return Unless overridden, the default is * Status.passed("exit code 0") * if the command exited with exit code 0, or * Status.failed("exit code " + exitCode) * otherwise. **/ protected Status getStatus(int exitCode, Status logStatus) { if (logStatus != null) { // verify that the status reported in the STDOUT of the test program // indeed matches the exit code of the test program's process. This should // catch issues where the test program's process might have run into issues // (like VM crash) after the status was reported on STDOUT final int logStatusExitCode = Status.exitCodes[logStatus.getType()]; if (logStatusExitCode == exitCode) { // correctly reported exit return logStatus; } final String errMsg = "unexpected exit code: " + exitCode + ", doesn't match exit status: \"" + logStatus + "\" which was" + " reported by the test process"; return Status.error(errMsg); } else if (statusTable != null) { Status s = statusTable.get(exitCode); return (s == null ? defaultStatus.augment("exit code: " + exitCode) : s); } else if (exitCode == 0) { return Status.passed("exit code 0"); } else { return Status.failed("exit code " + exitCode); } } private HashMap statusTable; private Status defaultStatus = Status.error("unknown reason"); private File execDir; private List cmd; private Map env; private PrintWriter out; private PrintWriter err; private long timeout; private TimeoutHandler timeoutHandler; } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/exec/RegressionScript.java000066400000000000000000001375531461415321300312670ustar00rootroot00000000000000/* * Copyright (c) 1997, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.exec; import java.io.File; import java.io.PrintWriter; import java.io.UncheckedIOException; import java.lang.reflect.Method; import java.net.InetAddress; import java.net.MalformedURLException; import java.net.UnknownHostException; import java.nio.file.Files; import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.EnumMap; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import java.util.function.Consumer; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; import java.util.stream.Collectors; import com.sun.javatest.Script; import com.sun.javatest.Status; import com.sun.javatest.TestDescription; import com.sun.javatest.TestEnvironment; import com.sun.javatest.TestResult; import com.sun.javatest.TestSuite; import com.sun.javatest.regtest.agent.JDK_Version; import com.sun.javatest.regtest.agent.MainWrapper; import com.sun.javatest.regtest.agent.SearchPath; import com.sun.javatest.regtest.config.ExecMode; import com.sun.javatest.regtest.config.Expr; import com.sun.javatest.regtest.config.IgnoreKind; import com.sun.javatest.regtest.config.JDK; import com.sun.javatest.regtest.config.JDKOpts; import com.sun.javatest.regtest.config.Locations; import com.sun.javatest.regtest.config.Locations.LibLocn; import com.sun.javatest.regtest.config.Modules; import com.sun.javatest.regtest.config.OS; import com.sun.javatest.regtest.config.ParseException; import com.sun.javatest.regtest.config.RegressionEnvironment; import com.sun.javatest.regtest.config.RegressionParameters; import com.sun.javatest.regtest.config.RegressionTestSuite; import com.sun.javatest.regtest.report.SummaryReporter; import com.sun.javatest.regtest.tool.Version; import com.sun.javatest.regtest.util.FileUtils; import com.sun.javatest.regtest.util.StringUtils; import static com.sun.javatest.regtest.RStatus.error; import static com.sun.javatest.regtest.RStatus.passed; /** * This class interprets the TestDescription as specified by the JDK tag * specification. * * @see com.sun.javatest.Script */ public class RegressionScript extends Script { /** * The method that interprets the tags provided in the test description and * performs actions accordingly. * * Any messages that are reported while accessing the {@link JDK} and related classes * will be reported to the main message section in the resulting {@code .jtr} file. * * @param argv Any arguments that the RegressionScript may use. Currently * there are none (value ignored). * @param td The current TestDescription. * @param env The test environment giving the details of how to run the * test. * @return The result of running the script on the given test * description. */ @Override public Status run(String[] argv, TestDescription td, TestEnvironment env) { if (!(env instanceof RegressionEnvironment)) throw new AssertionError(); long started = System.currentTimeMillis(); regEnv = (RegressionEnvironment) env; params = regEnv.params; testSuite = params.getTestSuite(); String filterFault = params.filterFaults.get(td.getRootRelativeURL()); if (filterFault != null) return Status.error(filterFault); Status status = passed("OK"); String actions = td.getParameter("run"); // System.out.println("--- ACTIONS: " + actions); // actions != null -- should never happen since we have reasonable // defaults testResult = getTestResult(); String hostname; try { hostname = InetAddress.getLocalHost().getCanonicalHostName(); } catch (UnknownHostException e) { hostname = "127.0.0.1"; } testResult.putProperty("hostname", hostname); String[] props = { "user.name" }; for (String p: props) { testResult.putProperty(p, System.getProperty(p)); } testResult.putProperty("jtregVersion", getVersion()); testResult.putProperty("testJDK", getTestJDK().getAbsolutePath()); OS testOs = params.getTestOS(); testResult.putProperty("testJDK_OS", testOs.toString()); testResult.putProperty("testJDK_os.name", testOs.name); testResult.putProperty("testJDK_os.version", testOs.version); testResult.putProperty("testJDK_os.arch", testOs.arch); if (!getCompileJDK().equals(getTestJDK())) { testResult.putProperty("compileJDK", getCompileJDK().getAbsolutePath()); } msgPW = testResult.getTestCommentWriter(); defaultModules = params.getTestJDK().getDefaultModules(params, msgPW::println); systemModules = params.getTestJDK().getSystemModules(params, msgPW::println); try { int maxOutputSize = testSuite.getMaxOutputSize(td); if (maxOutputSize > 0) { try { Method m = TestResult.class.getMethod("setMaxOutputSize", int.class); m.invoke(testResult, maxOutputSize); } catch (ReflectiveOperationException e) { System.err.println("Cannot set maxOutputSize in this build of jtreg: setting ignored"); } } locations = new Locations(params, td, msgPW::println); if (params.getTestJDK().hasModules()) { modules = new Modules(params, td); if (!modules.isEmpty()) testResult.putProperty("modules", modules.toString()); } else { modules = Modules.noModules; } // defaultExecMode may still be overridden in individual actions with /othervm defaultExecMode = testSuite.useOtherVM(td) ? ExecMode.OTHERVM : params.getExecMode(); useBootClassPath = testSuite.useBootClassPath(td.getRootRelativePath()); LinkedList actionList = parseActions(actions, true); needJUnit = false; needTestNG = false; for (Action a : actionList) { if (a instanceof JUnitAction) { needJUnit = true; } else if (a instanceof TestNGAction) { needTestNG = true; // check for using mixed-mode if (td.getParameter("importsJUnit") != null) { needJUnit = true; } } } if (needJUnit && !params.isJUnitAvailable()) { throw new TestRunException("JUnit not available: see the FAQ for details"); } if (needTestNG && !params.isTestNGAvailable()) { throw new TestRunException("TestNG not available: see the FAQ for details"); } if (!locations.absLibClsList(LibLocn.Kind.SYS_MODULE).isEmpty()) { usePatchModules = true; } else { // check actions for test-specific modules actionLoop: for (Action a : actionList) { for (String m : a.getModules()) { if (systemModules.contains(m)) { usePatchModules = true; break actionLoop; } } } } if (!locations.absLibClsList(LibLocn.Kind.USER_MODULE).isEmpty()) { useModulePath = true; } scratchDirectory = ScratchDirectory.get(params, defaultExecMode, td); scratchDirectory.init(msgPW); // if we got an error while parsing the TestDescription, return // error immediately if (td.getParameter("error") != null) status = error(td.getParameter("error")); else { if (getTestJDK().equals(getCompileJDK())) { // output for default case unchanged printJDKInfo(msgPW, "JDK under test", getTestJDK(), getTestVMOptions()); } else { printJDKInfo(msgPW, "compile JDK", getCompileJDK(), Collections.emptyList()); printJDKInfo(msgPW, "test JDK", getTestJDK(), getTestVMOptions()); } for (LibLocn lib : locations.getLibs()) { String kind; switch (lib.kind) { case PACKAGE: kind = "packages"; break; case PRECOMPILED_JAR: kind = "precompiled jar"; break; case SYS_MODULE: kind = "system module patches"; break; case USER_MODULE: kind = "user modules"; break; default: kind = "unknown"; } msgPW.println("Library " + lib.name + "; kind: " + kind); if (lib.absSrcDir != null) { msgPW.println(" source directory: " + lib.absSrcDir); } if (Files.isRegularFile(lib.absClsDir) && lib.absClsDir.getFileName().toString().endsWith(".jar")) { msgPW.println(" jar file: " + lib.absClsDir); } else { msgPW.println(" class directory: " + lib.absClsDir); } } while (!actionList.isEmpty()) { Action action = actionList.remove(); status = action.run(); if (status.getType() != Status.PASSED) break; } } } catch (InterruptedException e) { status = error("Interrupted! " + e.getLocalizedMessage()); } catch (ScratchDirectory.Fault e) { String msg = e.getLocalizedMessage(); if (e.getCause() != null) msg += " (" + e.getCause() + ")"; status = error(msg); } catch (Expr.Fault | Locations.Fault | Modules.Fault | ParseActionsException | TestRunException | TestSuite.Fault | FileUtils.NIOFileOperationException e) { status = error(e.getMessage()); } catch (UncheckedIOException e) { String msg = "IO exception: " + e.getMessage(); if (e.getCause() != null) msg += " (" + e.getCause() + ")"; status = error(msg); } catch (InvalidPathException e) { String msg = "Invalid path: " + e.getInput() + "; " + e.getMessage(); if (e.getCause() != null) msg += " (" + e.getCause() + ")"; status = error(msg); } finally { int elapsed = (int) (System.currentTimeMillis() - started); int millis = (elapsed % 1000); int secs = (elapsed / 1000) % 60; int mins = (elapsed / (1000 * 60)) % 60; int hours = elapsed / (1000 * 60 * 60); testResult.putProperty("elapsed", String.format("%d %d:%02d:%02d.%03d", elapsed, hours, mins, secs, millis)); if (scratchDirectory != null && params.isRetainEnabled()) { String errmsg = null; try { scratchDirectory.retainFiles(status, msgPW); } catch (InterruptedException e) { errmsg = "Interrupted! " + e.getLocalizedMessage(); } catch (ScratchDirectory.Fault e) { errmsg = e.getMessage(); if (e.getCause() != null) errmsg += " (" + e.getCause() + ")"; } if (errmsg != null) { msgPW.println(errmsg); msgPW.println("WARNING: failed to clean up files after test"); if (!agents.isEmpty()) { msgPW.println("WARNING: closing agent(s)"); } closeAgents(); } } releaseAgents(); } return status; } // run() private void printJDKInfo(PrintWriter pw, String label, JDK jdk, List opts) { pw.print(label); pw.print(": "); pw.println(jdk.getAbsoluteHomeDirectory()); String v = jdk.getVersionText(opts, pw::println); if (v.length() > 0) { pw.println(v); } } /** * Get the set of source files used by the actions in a test description. * @param p The parameters providing the necessary context * @param td The test description for which to find the test files * @return the set of source files known to the test **/ public static Set getSourceFiles(RegressionParameters p, TestDescription td) { Consumer logger = System.err::println; try { RegressionScript tmp = new RegressionScript(); // init the script enough to parse the actions tmp.params = p; tmp.td= td; tmp.locations = new Locations(p, td, logger); tmp.modules = new Modules(p, td); tmp.defaultModules = p.getTestJDK().getDefaultModules(p, logger); tmp.systemModules = p.getTestJDK().getSystemModules(p, logger); String actions = td.getParameter("run"); LinkedList actionList = tmp.parseActions(actions, false); Set files = new TreeSet<>(); while (! actionList.isEmpty()) { Action action = actionList.remove(); Set a = action.getSourceFiles(); if (a != null) files.addAll(a); } return files; } catch (Expr.Fault | Locations.Fault | Modules.Fault | ParseException | TestSuite.Fault e) { return Collections.emptySet(); } catch (ParseActionsException shouldNotHappen) { throw new Error(shouldNotHappen); } } static class ParseActionsException extends Exception { static final long serialVersionUID = -3369214582449830917L; ParseActionsException(String msg) { super(msg); } } /** * Parse a sequence of actions. * * @param actions a series of actions, separated by LINESEP * @param stopOnError whether or not to ignore any parse errors; if true and an error * is found, a ParseActionsException will be thrown, giving a detail message. * @return a Fifo of Action objects */ LinkedList parseActions(String actions, boolean stopOnError) throws ParseActionsException, ParseException, TestSuite.Fault, Expr.Fault { LinkedList actionList = new LinkedList<>(); String[] runCmds = StringUtils.splitTerminator(LINESEP, actions); populateActionTable(); Expr.Context exprContext = params.getExprContext(); Map testProps = getTestProperties(); for (String runCmd : runCmds) { // e.g. reason compile/fail/ref=Foo.ref -debug Foo.java // where "reason" indicates why the action should run String[] tokens = StringUtils.splitWS(runCmd); // [reason, compile/fail/ref=Foo.ref, -debug, Foo.java] String[] verbopts = StringUtils.splitSeparator("/", tokens[1]); // [compile, fail, ref=Foo.ref] String verb = verbopts[0]; Map opts = new LinkedHashMap<>(); for (int i = 1; i < verbopts.length; i++) { String[] keyValue = StringUtils.splitEqual(verbopts[i]); opts.put(keyValue[0], keyValue[1]); // [[fail,], [ref, Foo.ref]] } List args = new ArrayList<>(Arrays.asList(tokens).subList(2, tokens.length)); // [-debug, Foo.java] (everything after the big options token) Class c = null; try { c = actionTable.get(verb); if (c == null) { if (stopOnError) throw new ParseActionsException(BAD_ACTION + verb); continue; } Action action = (Action) (c.getDeclaredConstructor().newInstance()); action.init(opts, processArgs(args, exprContext, testProps), getReason(tokens), this); actionList.add(action); } catch (IllegalAccessException e) { if (stopOnError) throw new ParseActionsException(ILLEGAL_ACCESS_INIT + c); } catch (ReflectiveOperationException e) { if (stopOnError) throw new ParseActionsException(CANT_INSTANTIATE + c + NOT_EXT_ACTION); } } return actionList; } boolean enablePreview() { String ep = td.getParameter("enablePreview"); return ep != null && ep.equals("true"); } private List processArgs(List args, Expr.Context c, Map testProps) throws TestSuite.Fault, Expr.Fault, ParseException { if (!testSuite.getAllowSmartActionArgs(td)) return args; boolean fast = true; for (String arg : args) { fast = fast && (!arg.contains("${")); } if (fast) { return args; } List newArgs = new ArrayList<>(); for (String arg : args) { newArgs.add(evalNames(arg, c, testProps)); } return newArgs; } private static final Pattern namePattern = Pattern.compile("\\$\\{([A-Za-z0-9._]+)}"); private static String evalNames(String arg, Expr.Context c, Map testProps) throws Expr.Fault, ParseException { Matcher m = namePattern.matcher(arg); StringBuilder sb = null; // Note that '\' may appear in the replacement value for paths on Windows, // and so, in the following loop, avoid using Matcher::appendReplacement, // which interprets '\' and `$' in the replacement string. // Instead, use explicit operations to append the literal replacement value. int pos = 0; while (m.find(pos)) { if (sb == null) { sb = new StringBuilder(); } String name = m.group(1); String value = testProps.containsKey(name) ? testProps.get(name) : c.get(name); if ("null".equals(value)) { throw new ParseException("unset property " + name); } sb.append(arg, pos, m.start()); sb.append(value); pos = m.end(); } if (sb == null) { return arg; } else { sb.append(arg.substring(pos)); return sb.toString(); } } //---------- methods for timing -------------------------------------------- /** * Get the timeout to be used for a test. Since the timeout for regression * tests is on a per-action basis rather than on a per-test basis, this * method should always return zero which indicates that there is no * timeout. * * @return 0 */ @Override protected int getTestTimeout() { return 0; } /** * Returns the timeout to be used for an action. * * If no debug options have been set, the result will be the given value, * or a default value if the given value is negative, scaled by the timeout factor. * * If debug options have been set, the result will be 0, meaning "no timeout". * * @param time the value of the timeout specified in the action, * or -1 if no value was specified * @return the timeout, in seconds */ protected int getActionTimeout(int time) { final int DEFAULT_ACTION_TIMEOUT = 120; // seconds return isTimeoutsEnabled() ? (int) ((time < 0 ? DEFAULT_ACTION_TIMEOUT : time) * getTimeoutFactor()) : 0; } protected float getTimeoutFactor() { if (cacheJavaTestTimeoutFactor == -1) { // not synchronized, so in worst case may be set more than once float value = 1; // default try { // The timeout factor is available as both an integer (for backward compatibility) // and a floating point number. // Use [1] to get the floating point timeout factor String f = (regEnv == null ? null : regEnv.lookup("javatestTimeoutFactor")[1]); if (f != null) value = Float.parseFloat(f); } catch (TestEnvironment.Fault | NumberFormatException e) { } cacheJavaTestTimeoutFactor = value; } return cacheJavaTestTimeoutFactor; } private static float cacheJavaTestTimeoutFactor = -1; /** * Returns whether timeouts are (generally) enabled. * * @return {@code true} if timeouts are enabled, and {@code false} otherwise */ protected boolean isTimeoutsEnabled() { // for now, timeouts are always enabled, unless debug options have been specified for the test return getTestDebugOptions().isEmpty(); } /** * Set an alarm that will interrupt the calling thread after a specified * delay (in milliseconds), and repeatedly thereafter until canceled. The * testCommentWriter will contain a confirmation string indicating that a * timeout has been signaled. * * @param timeout The delay in milliseconds. */ @Override protected void setAlarm(int timeout) { super.setAlarm(timeout); } //----------internal methods------------------------------------------------ private void populateActionTable() { addAction(AppletAction.NAME, AppletAction.class); addAction(BuildAction.NAME, BuildAction.class); addAction(CleanAction.NAME, CleanAction.class); addAction(CompileAction.NAME, CompileAction.class); addAction(DriverAction.NAME, DriverAction.class); addAction(IgnoreAction.NAME, IgnoreAction.class); addAction(JUnitAction.NAME, JUnitAction.class); addAction(MainAction.NAME, MainAction.class); addAction(ShellAction.NAME, ShellAction.class); addAction(TestNGAction.NAME, TestNGAction.class); } // populateActionTable() private void addAction(String actionName, Class actionClass) { actionTable.put(actionName, actionClass); } // addAction() /** * Decode the reason and set the appropriate string. At this point, we * should only get reasons that are generated by the test finder. * * @param cmd The command we will run. Includes the encoded reason. */ private String getReason(String[] cmd) { String retVal; StringBuilder sb = new StringBuilder(); String reason = cmd[0]; switch (reason) { case Action.REASON_ASSUMED_ACTION: for (int i = 1; i < cmd.length; i++) sb.append(cmd[i]).append(" "); retVal = Action.SREASON_ASSUMED_ACTION + sb; break; case Action.REASON_USER_SPECIFIED: for (int i = 1; i < cmd.length; i++) sb.append(cmd[i]).append(" "); retVal = Action.SREASON_USER_SPECIFIED + sb; break; default: retVal = "Unknown"; break; } return retVal; } // getReason() /** * Determine whether environment variables have been tunneled using the * following syntax: -DenvVars="name0=value0,name1=value1". If they * have, return a map of name=value pairs. Otherwise, return an empty map. * * @return A map containing the tunneled environment variables. */ Map getEnvVars() { return params.getEnvVars(); } /** * Determine whether we just want to check the validity of the * user-provided test description without actually running the test. */ boolean isCheck() { return params.isCheck(); } /** * VM options for otherJVM tests */ List getTestVMOptions() { return params.getTestVMOptions(); } /** * Tool VM options for otherJVM tests */ List getTestToolVMOptions() { return params.getTestToolVMOptions(); } /** * VM options and java for otherJVM tests */ List getTestVMJavaOptions() { return params.getTestVMJavaOptions(); } /** * Debug options for tests */ List getTestDebugOptions() { return params.getTestDebugOptions(); } /** * compiler options */ List getTestCompilerOptions() { return params.getTestCompilerOptions(); } /** * java command options */ List getTestJavaOptions() { return params.getTestJavaOptions(); } /** * What to do with @ignore tags */ IgnoreKind getIgnoreKind() { return params.getIgnoreKind(); } /** * Path to native components. */ Path getNativeDir() { return params.getNativeDir(); } /** * Returns the version of jtreg required by this test suite. */ Version getRequiredVersion() { return params.getTestSuite().getRequiredVersion(); } /** * Get content of @modules. */ Modules getModules() { return modules; } Set getLibBuildArgs() throws TestRunException { try { return testSuite.getLibBuildArgs(td); } catch (TestSuite.Fault e) { throw new TestRunException(e.getMessage(), e); } } Pattern getIgnoreRefLinesPattern() throws TestRunException { try { return params.getRefIgnoreLinesPattern(); } catch (PatternSyntaxException e) { // this exception will only occur at most once per test run throw new TestRunException(e.getMessage(), e); } } String getTestQuery() { String testName = testResult.getTestName(); return params.getTestQuery(testName); } //----------------------- computing paths --------------------------------- Path absTestWorkFile(String name) { return locations.absTestWorkFile(name); } Path absTestSrcDir() { return locations.absTestSrcDir(); } // absTestSrcDir() Path absTestClsDir() { return locations.absTestClsDir(); } // absTestClsDir() Path absTestScratchDir() { return scratchDirectory.dir.toPath().toAbsolutePath(); } // absTestScratchDir() Path absTestClsTopDir() { return locations.absBaseClsDir(); } // absTestClsTopDir() private boolean useBootClassPath(Path classdir) throws TestClassException { try { String rel = locations.absBaseClsDir().toUri().relativize(classdir.toFile().toURI()).getPath(); return testSuite.useBootClassPath(rel); } catch (TestSuite.Fault f) { throw new TestClassException(f.toString()); } } enum PathKind { BOOTCLASSPATH_APPEND, CLASSPATH, MODULEPATH, MODULESOURCEPATH, PATCHPATH, SOURCEPATH } Map getCompilePaths(LibLocn libLocn, boolean multiModule, String module) throws TestRunException { SearchPath bcp = new SearchPath(); SearchPath cp = new SearchPath(); SearchPath mp = new SearchPath(); SearchPath msp = new SearchPath(); SearchPath pp = new SearchPath(); SearchPath sp = new SearchPath(); // Test: if (libLocn == null || libLocn.name == null) { if (multiModule) { msp.append(locations.absTestSrcDir()); } else { Path testSrcDir = locations.absTestSrcDir(module); sp.append(testSrcDir); // Ideally, the source directory need only go on the source path // but some tests rely on precompiled .class files existing in // the source directory. Allow such legacy usage for package- // oriented tests, and also put the source dir on classpath. // Note: it is not enough to just put it on the classpath only // in those cases where there are other items on the source path. cp.append(testSrcDir); } } if (!multiModule) cp.append(locations.absTestClsDir()); if (useModulePath()) { mp.append(locations.absTestModulesDir()); } if (usePatchModules()) { pp.append(locations.absTestPatchDir()); } // Libraries: if (libLocn != null) { if (multiModule) msp.append(libLocn.absSrcDir); else if (module != null) sp.append(libLocn.absSrcDir.resolve(module)); } if (module == null) { sp.append(locations.absLibSrcList(LibLocn.Kind.PACKAGE)); } // could split stuff onto bootclasspath to match execution paths, but not necessary cp.append(locations.absLibClsList(LibLocn.Kind.PACKAGE)); cp.append(locations.absLibSrcJarList()); if (useModulePath()) { mp.append(locations.absLibClsList(LibLocn.Kind.USER_MODULE)); } if (usePatchModules()) { pp.append(locations.absLibClsList(LibLocn.Kind.SYS_MODULE)); } // Frameworks: if (multiModule) { if (needJUnit || needTestNG) { // Put necessary jar files onto the module path as automatic modules. // We cannot use the ${jtreg.home}/lib directory directly since it contains // other jar files which are not valid as automatic modules. if (needJUnit) params.getJUnitPath().asList().forEach(mp::append); if (needTestNG) params.getTestNGPath().asList().forEach(mp::append); } } else { if (needJUnit) cp.append(params.getJUnitPath()); if (needTestNG) cp.append(params.getTestNGPath()); } // Extras: // tools.jar, when present JDK jdk = getCompileJDK(); cp.append(jdk.getJDKClassPath()); // handle cpa option to jtreg Map envVars = getEnvVars(); String cpa = envVars.get("CPAPPEND"); if (cpa != null) { // the cpa we were passed always uses '/' as FILESEP, make // sure to use the proper one for the platform cpa = cpa.replace('/', File.separatorChar); cp.append(cpa); } // Results: Map map = new EnumMap<>(PathKind.class); if (!bcp.isEmpty()) map.put(PathKind.BOOTCLASSPATH_APPEND, bcp); if (!cp.isEmpty()) map.put(PathKind.CLASSPATH, cp); if (!mp.isEmpty()) map.put(PathKind.MODULEPATH, mp); if (!msp.isEmpty()) map.put(PathKind.MODULESOURCEPATH, msp); if (!pp.isEmpty()) map.put(PathKind.PATCHPATH, pp); if (!sp.isEmpty()) map.put(PathKind.SOURCEPATH, sp); return map; } Map getExecutionPaths( boolean multiModule, String module, boolean testOnBootClassPath, boolean include_jtreg) throws TestRunException { SearchPath bcp = new SearchPath(); SearchPath cp = new SearchPath(); SearchPath mp = new SearchPath(); SearchPath pp = new SearchPath(); // Test: SearchPath tp = testOnBootClassPath ? bcp : cp; tp.append(locations.absTestClsDir()); tp.append(locations.absTestSrcDir()); // include source dir for access to resource files if (hasTestPatchMods()) { pp.append(locations.absTestPatchDir()); } if (hasTestUserMods()) { mp.append(locations.absTestModulesDir()); } // Libraries: if (testOnBootClassPath) { // all libraries unconditionally also on bootclasspath bcp.append(locations.absLibClsList(LibLocn.Kind.PACKAGE)); bcp.append(locations.absLibSrcJarList()); } else { // only put libraries on bootclasspath that need to be there for (LibLocn libLocn: locations.getLibs()) { if (libLocn.kind == LibLocn.Kind.PACKAGE) { SearchPath p = (useBootClassPath(libLocn.absClsDir)) ? bcp : cp; p.append(libLocn.absClsDir); p.append(libLocn.absSrcDir); // include source dir for access to resource files } } cp.append(locations.absLibSrcJarList()); } if (useModulePath()) { mp.append(locations.absLibClsList(LibLocn.Kind.USER_MODULE)); } if (usePatchModules()) { pp.append(locations.absLibClsList(LibLocn.Kind.SYS_MODULE)); } // Frameworks: if (multiModule) { // assert !testOnBootClassPath && !useXPatch() if (needJUnit || needTestNG) { // Put necessary jar files onto the module path as automatic modules. // We cannot use the ${jtreg.home}/lib directory directly since it contains // other jar files which are not valid as automatic modules. if (needJUnit) params.getJUnitPath().asList().forEach(mp::append); if (needTestNG) params.getTestNGPath().asList().forEach(mp::append); } } else { SearchPath fp = (!bcp.isEmpty() || usePatchModules()) ? bcp : cp; if (needJUnit) fp.append(params.getJUnitPath()); if (needTestNG) fp.append(params.getTestNGPath()); } // Extras: // tools.jar, when present JDK jdk = getCompileJDK(); tp.append(jdk.getJDKClassPath()); // handle cpa option to jtreg Map envVars = getEnvVars(); String cpa = envVars.get("CPAPPEND"); if (cpa != null) { // the cpa we were passed always uses '/' as FILESEP, make // sure to use the proper one for the platform cpa = cpa.replace('/', File.separatorChar); cp.append(cpa); } // javatest.jar and jtreg.jar if (include_jtreg) { (testOnBootClassPath ? bcp : cp).append(getJavaTestClassPath()); } Map map = new EnumMap<>(PathKind.class); if (!bcp.isEmpty()) map.put(PathKind.BOOTCLASSPATH_APPEND, bcp); if (!cp.isEmpty()) map.put(PathKind.CLASSPATH, cp); if (!mp.isEmpty()) map.put(PathKind.MODULEPATH, mp); if (!pp.isEmpty()) map.put(PathKind.PATCHPATH, pp); return map; } boolean useBootClassPath() { return useBootClassPath; } boolean usePatchModules() { return usePatchModules; } boolean hasTestPatchMods() { Path testModulesDir = locations.absTestPatchDir(); if (Files.isDirectory(testModulesDir)) { for (Path f : FileUtils.listFiles(testModulesDir)) { if (Files.isDirectory(f)) return true; } } return false; } // currently unused boolean useModulePath() { return useModulePath; } boolean hasTestUserMods() { Path testModulesDir = locations.absTestModulesDir(); if (Files.isDirectory(testModulesDir)) { for (Path f : FileUtils.listFiles(testModulesDir)) { if (Files.isDirectory(f)) return true; } } return false; } ExecMode getExecMode() { return defaultExecMode; } SearchPath getJavaTestClassPath() { return params.getJavaTestClassPath(); } boolean isJUnitRequired() { return needJUnit; } SearchPath getJUnitPath() { return params.getJUnitPath(); } boolean isTestNGRequired() { return needTestNG; } SearchPath getTestNGPath() { return params.getTestNGPath(); } SearchPath getAsmToolsPath() { return params.getAsmToolsPath(); } SummaryReporter getTestNGSummaryReporter() { return SummaryReporter.forTestNG(workDir); } SummaryReporter getJUnitSummaryReporter() { return SummaryReporter.forJUnit(workDir); } Lock getLockIfRequired() throws TestRunException { try { if (!testSuite.needsExclusiveAccess(td)) return null; } catch (TestSuite.Fault e) { throw new TestRunException("Can't determine if lock required", e); } return Lock.get(params); } int getNextSerial() { return nextSerial++; } private int nextSerial = 0; PrintWriter getMessageWriter() { return msgPW; } //-------------------------------------------------------------------------- TimeoutHandlerProvider getTimeoutHandlerProvider() throws TestRunException { try { return params.getTimeoutHandlerProvider(); } catch (MalformedURLException e) { throw new TestRunException("Can't get timeout handler provider", e); } } String getTestThreadFactory() { return params.getTestThreadFactory(); } String getTestThreadFactoryPath() { return params.getTestThreadFactoryPath(); } //-------------------------------------------------------------------------- JDK getTestJDK() { return params.getTestJDK(); } JDK_Version getTestJDKVersion() { return getTestJDK().getVersion(params, msgPW::println); } Path getJavaProg() { return params.getTestJDK().getJavaProg(); } //-------------------------------------------------------------------------- JDK getCompileJDK() { return params.getCompileJDK(); } JDK_Version getCompileJDKVersion() { return getCompileJDK().getVersion(params, msgPW::println); } Path getJavacProg() { return params.getCompileJDK().getJavacProg(); } //-------------------------------------------------------------------------- // Get the standard properties to be set for tests Map getTestProperties() { // initialize the properties with standard properties common to all tests Map p = new LinkedHashMap<>(params.getBasicTestProperties()); // add test-specific properties String testName = testResult.getTestName(); p.put("test.name", testName); String testQuery = params.getTestQuery(testName); if (testQuery != null) { p.put("test.query", testQuery); } p.put("test.file", locations.absTestFile().toString()); p.put("test.src", locations.absTestSrcDir().toString()); p.put("test.src.path", toString(locations.absTestSrcPath())); p.put("test.classes", locations.absTestClsDir().toString()); p.put("test.class.path", toString(locations.absTestClsPath())); if (getExecMode() == ExecMode.AGENTVM) { // The following will be added to javac.class.path on the test VM SearchPath path = new SearchPath() .append(locations.absTestClsDir()) .append(locations.absTestSrcDir()) .append(locations.absLibClsList(LibLocn.Kind.PACKAGE)) .append(locations.absLibSrcJarList()); p.put("test.class.path.prefix", path.toString()); } if (!modules.isEmpty()) p.put("test.modules", modules.toString()); if (usePatchModules()) { SearchPath pp = new SearchPath(); pp.append(locations.absLibClsList(LibLocn.Kind.SYS_MODULE)); p.put("test.patch.path", pp.toString()); } if (useModulePath()) { SearchPath pp = new SearchPath(); pp.append(locations.absLibClsList(LibLocn.Kind.USER_MODULE)); p.put("test.module.path", pp.toString()); } if (enablePreview()) { p.put("test.enable.preview", "true"); } p.put("test.root", getTestRootDir().getPath()); return Collections.unmodifiableMap(p); } // where private String toString(List files) { return files.stream() .map(Path::toString) .collect(Collectors.joining(File.pathSeparator)); } // // where // private String toString(List files) { // return files.stream() // .map(File::getPath) // .collect(Collectors.joining(File.pathSeparator)); // } File getTestRootDir() { return params.getTestSuite().getRootDir(); } //-------------------------------------------------------------------------- /* * Get an agent for a VM with the given VM options. */ Agent getAgent(JDK jdk, SearchPath classpath, List testVMOpts, String testThreadFactory, String testThreadFactoryPath) throws Agent.Fault { JDKOpts vmOpts = new JDKOpts(); vmOpts.addAll("-classpath", classpath.toString()); vmOpts.addAll(testVMOpts); if (testThreadFactory != null) { // Add property to differ agents with and without MainWrapper vmOpts.add("-D" + MainWrapper.TEST_THREAD_FACTORY + "=" + testThreadFactory); } if (params.getTestJDK().hasModules()) { vmOpts.addAllPatchModules(new SearchPath(params.getWorkDirectory().getFile("patches").toPath())); } /* * A script only uses one agent at a time, and only one, maybe two, * different agents overall, for actions that use agentVM mode (i.e. * CompileAction and MainAction.) Therefore, use a simple list to * record the agents that the script has already obtained for use. */ for (Agent agent: agents) { if (agent.matches(absTestScratchDir().toFile(), jdk, vmOpts.toList())) { return agent; } } Map envVars = new HashMap<>(getEnvVars()); // some tests are inappropriately relying on the CLASSPATH environment // variable being set, so ensure it is set. See equivalent code in MainAction // and Main.execChild. Note we cannot set exactly the same classpath as // for othervm, because we should not include test-specific info SearchPath cp = new SearchPath().append(jdk.getJDKClassPath()).append(getJavaTestClassPath()); envVars.put("CLASSPATH", cp.toString()); Agent.Pool p = Agent.Pool.instance(params); Agent agent = p.getAgent(absTestScratchDir().toFile(), jdk, vmOpts.toList(), envVars, testThreadFactory, testThreadFactoryPath); agents.add(agent); return agent; } /** * Close an agent, typically because an error has occurred while using it. */ void closeAgent(Agent agent) { agent.close(); agents.remove(agent); } /* * Close all the agents this script has obtained for use. This will * terminate the VMs used by those agents. */ void closeAgents() { for (Agent agent: agents) { agent.close(); } agents.clear(); } /* * Release all the agents this script has obtained for use. * The agents are made available for future reuse. */ void releaseAgents() { if (!agents.isEmpty()) { Agent.Pool pool = Agent.Pool.instance(params); for (Agent agent: agents) { pool.save(agent); } } } List agents = new ArrayList<>(); //-------------------------------------------------------------------------- boolean useWindowsSubsystemForLinux() { return params.useWindowsSubsystemForLinux(); } //----------internal classes----------------------------------------------- void saveScratchFile(Path file, Path dest) { scratchDirectory.retainFile(file.toFile(), dest.toFile()); } //----------internal classes----------------------------------------------- /* * Exception used to indicate that there is a problem with the destination * of class files generated by the actual tests. */ public static class TestClassException extends TestRunException { private static final long serialVersionUID = -5087319602062056951L; public TestClassException(String msg) { super("Test Class Exception: " + msg); } // TestClassException() } private static String getVersion() { if (version == null) { StringBuilder sb = new StringBuilder(); Version v = Version.getCurrent(); sb.append(v.product == null ? "jtreg" : v.product); if (v.version != null) sb.append(' ').append(v.version); if (v.milestone != null) sb.append(' ').append(v.milestone); if (v.build != null) sb.append(' ').append(v.build); version = sb.toString(); } return version; } // where private static String version; //----------misc statics--------------------------------------------------- private static final String LINESEP = System.getProperty("line.separator"); private static final String CANT_INSTANTIATE = "Unable to instantiate: ", NOT_EXT_ACTION = " does not extend Action", ILLEGAL_ACCESS_INIT = "Illegal access to init method: ", BAD_ACTION = "Bad action for script: "; //----------member variables----------------------------------------------- private final Map> actionTable = new HashMap<>(); private TestResult testResult; private RegressionEnvironment regEnv; private RegressionParameters params; private RegressionTestSuite testSuite; private PrintWriter msgPW; Set defaultModules; Set systemModules; private boolean useBootClassPath; private boolean usePatchModules; private boolean useModulePath; private ExecMode defaultExecMode; private boolean needJUnit; private boolean needTestNG; private Modules modules; private ScratchDirectory scratchDirectory; Locations locations; } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/exec/ScratchDirectory.java000066400000000000000000000436671461415321300312400ustar00rootroot00000000000000/* * Copyright (c) 1997, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.exec; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Pattern; import com.sun.javatest.Status; import com.sun.javatest.TestDescription; import com.sun.javatest.TestResult; import com.sun.javatest.regtest.agent.Flags; import com.sun.javatest.regtest.config.ExecMode; import com.sun.javatest.regtest.config.RegressionParameters; /** * Utilities for handling the scratch directory in which tests are executed. */ abstract class ScratchDirectory { /** Used to report serious issues while manipulating the scratch directory. */ static class Fault extends Exception { private static final long serialVersionUID = 0; Fault(String msg) { super(msg); } Fault(String msg, Throwable cause) { super(msg, cause); } } /** Get a scratch directory appropriate for the given parameters. */ static ScratchDirectory get(RegressionParameters params, ExecMode mode, TestDescription td) { if (mode == ExecMode.OTHERVM && params.isRetainEnabled()) return new TestResultScratchDir(params, td); else return new ThreadSafeScratchDir(params, td); } private static final boolean verboseScratchDir = Flags.get("verboseScratchDir"); /** The execution parameters for the current test. */ protected final RegressionParameters params; /** The current test. */ protected final TestDescription td; /** The current location of the scratch directory. */ File dir; protected ScratchDirectory(RegressionParameters params, TestDescription td, File dir) { this.params = params; this.td = td; this.dir = dir; } // /** * Initialize a scratch directory. * Normally, this means deleting the contents of the directory. * If any file cannot be deleted, it is retried a few times, after a * short interval. * @param log A stream to which to write messages about any issues encountered. * @throws ScratchDirectory.Fault if the directory cannot be initialized. * @throws InterruptedException if the method is interrupted. */ void init(PrintWriter log) throws Fault, InterruptedException { if (dir.exists()) { try { deleteFiles(dir, null, false, log); } catch (Fault e) { addBadDir(dir); Agent.Pool.close(params, dir); throw e; } } else { if (!dir.mkdirs()) { throw new Fault(CANT_CREATE + dir); } } } private static final Set badDirs = new HashSet<>(); private static synchronized boolean isBadDir(File dir) { return badDirs.contains(dir); } private static synchronized void addBadDir(File dir) { badDirs.add(dir); } // // abstract void retainFiles(Status status, PrintWriter log) throws Fault, InterruptedException; boolean retainFile(File file, File dest) { File f = new File(dir, file.getPath()); File d = params.getWorkDirectory().getFile(dest.getPath()); return f.renameTo(d); } // // /** * Delete all files in a directory that optionally match or don't * match a pattern. * @throws Fault if any unexpected issues occur while deleting the contents * of the directory. * @throws InterruptedException */ protected void deleteFiles(File dir, Pattern p, boolean match, PrintWriter log) throws Fault, InterruptedException { if (isBadDir(dir)) throw new Fault(CANT_CLEAN + dir); try { if (!dir.exists()) { if (verboseScratchDir) log.println("WARNING: dir " + dir + " already deleted."); return; } deleteFilesWithRetry(dir, p, match, log); } catch (SecurityException e) { throw new Fault(SECMGR_EXC + dir, e); } } /** * Delete all files in a directory that optionally match or don't * match a pattern. * On Windows, files cannot be deleted if they are still open. * So, if files cannot be deleted, we pause and try again. * @throws Fault * @throws InterruptedException */ private void deleteFilesWithRetry(File dir, Pattern p, boolean match, PrintWriter log) throws Fault, InterruptedException { long startTime = System.currentTimeMillis(); Set cantDelete = new LinkedHashSet<>(); do { if (deleteFiles(dir, p, match, false, cantDelete, log)) { return; } System.gc(); // allow finalizers and cleaners to run Thread.sleep(RETRY_DELETE_MILLIS); } while ((System.currentTimeMillis() - startTime) <= MAX_RETRY_DELETE_MILLIS); // report the list of files that could not be deleted for (File f: cantDelete) log.println("Can't delete " + f); throw new Fault(CANT_CLEAN + dir); } private static final int RETRY_DELETE_MILLIS; private static final int MAX_RETRY_DELETE_MILLIS; static { boolean isWindows = System.getProperty("os.name").startsWith("Windows"); RETRY_DELETE_MILLIS = isWindows ? 500 : 0; MAX_RETRY_DELETE_MILLIS = isWindows ? 15 * 1000 : 0; } /** * Delete all files in a directory that optionally match or don't * match a pattern. If deleteDir is set and all files in the directory * are deleted, the directory is deleted as well. * @throws Fault * @returns true if the selected files and directories are deleted successfully. */ private boolean deleteFiles(File dir, Pattern p, boolean match, boolean deleteDir, Set badFiles, PrintWriter log) throws Fault, InterruptedException { if (!dir.exists()) return true; boolean ok = true; File[] children = dir.listFiles(); if (children == null) { // should always be not null, but may be null if an error occurs log.println("warning: cannot list contents of directory " + dir); ok = false; } else { for (File file: children) { if (isDirectory(file)) { ok &= deleteFiles(file, p, match, true, badFiles, log); } else { boolean deleteFile = (p == null) || (p.matcher(file.getName()).matches() == match); if (deleteFile && !delete(file, badFiles, log)) { ok = false; } } } } if (ok && isEmpty(dir) && deleteDir) { ok = delete(dir, badFiles, log); } return ok; } private boolean delete(File f, Set cantDelete, PrintWriter log) { // optimistically assume the enclosing directory is writable if (f.delete() && !f.exists()) { cantDelete.remove(f); return true; } // retry if the enclosing directory was not writable and can be made writable File dir = f.getParentFile(); if (dir != null && !dir.canWrite() && setWritable(dir, log)) { return delete(f, cantDelete, log); } if (verboseScratchDir) { log.println("warning: failed to delete " + (f.isDirectory() ? "directory " : "") + f); } cantDelete.add(f); return false; } private boolean setWritable(File dir, PrintWriter log) { // optimistically assume the enclosing directory is writable if (dir.setWritable(true)) { return true; } // retry if the enclosing directory was not writable and can be made writable File parent = dir.getParentFile(); if (parent != null && !parent.canWrite() && setWritable(parent, log)) { return setWritable(dir, log); } if (verboseScratchDir) { log.println("warning: failed to set directory writable: " + dir); } return false; } // // /** * Copy all files in a directory that optionally match or don't match a pattern. * @throws InterruptedException **/ protected boolean saveFiles(File fromDir, File toDir, Pattern p, boolean match, PrintWriter log) throws InterruptedException { boolean result = true; boolean toDirExists = toDir.exists(); if (toDirExists) { // clean out the target directory before doing the copy to it try { deleteFiles(toDir, null, false, log); } catch (Fault e) { log.println("warning: could not empty " + toDir + ": " + e.getMessage()); } } for (File file: fromDir.listFiles()) { String fileName = file.getName(); if (file.isDirectory()) { File dest = new File(toDir, fileName); result &= saveFiles(file, dest, p, match, log); } else { boolean save = (p == null) || (p.matcher(fileName).matches() == match); if (save) { if (!toDirExists) { toDir.mkdirs(); toDirExists = toDir.exists(); } File dest = new File(toDir, fileName); if (dest.exists()) dest.delete(); boolean ok = file.renameTo(dest); if (!ok) { log.println("error: failed to rename " + file + " to " + dest); result = false; } } } } return result; } // // private static boolean isDirectory(File dir) throws Fault { try { return (dir.isDirectory() && dir.equals(dir.getCanonicalFile())); } catch (IOException e) { throw new Fault(CANON_FILE_EXC + dir, e); } } private static boolean isEmpty(File dir) { return dir.isDirectory() && (dir.listFiles().length == 0); } protected static File getResultDir(RegressionParameters params, TestDescription td) { String wrp = TestResult.getWorkRelativePath(td); // assert wrp.endsWith(".jtr") if (wrp.endsWith(".jtr")) wrp = wrp.substring(0, wrp.length() - 4); return params.getWorkDirectory().getFile(wrp); } // private static final String CANT_CLEAN = "Can't clean ", CANT_CREATE = "Can't create ", CANT_SAVE = "Can't save files in ", SECMGR_EXC = "Problem deleting file: ", CANON_FILE_EXC = "Problem determining canonical file: "; /** * Simple, basic scratch directory, in workdir/scratch, for agentvm mode */ static class SimpleScratchDirectory extends ScratchDirectory { SimpleScratchDirectory(RegressionParameters params, TestDescription td) { this(params, td, params.getWorkDirectory().getFile("scratch")); } protected SimpleScratchDirectory(RegressionParameters params, TestDescription td, File dir) { super(params, td, dir); } @Override void retainFiles(Status status, PrintWriter log) throws InterruptedException, Fault { // The scratchDir is not the same as resultDir, so we need to // save the files we want and delete the rest. boolean ok; File resultDir = getResultDir(params, td); if (params.getRetainStatus().contains(status.getType())) { // save all files; no need to delete any files ok = saveFiles(dir, resultDir, null, false, log); } else { Pattern rp = params.getRetainFilesPattern(); if (rp != null) { // save files which need to be retained ok = saveFiles(dir, resultDir, rp, true, log); } else { // test result doesn't match status set, no patterns specified: // no files need saving ok = true; } } if (!ok) throw new Fault(CANT_SAVE + dir); // delete any files remaining in the scratch dir deleteFiles(dir, null, false, log); } } /** * Use a thread-specific series of directories for the scratch directory. * Each thread gets its own series of directories to reuse for tests * executed by that thread. If a directory in the series cannot be cleaned * up after previous tests, the next directory in the series is used. */ static class ThreadSafeScratchDir extends SimpleScratchDirectory { private static class ThreadInfo { private static AtomicInteger counter = new AtomicInteger(); final int threadNum; int serial; ThreadInfo() { threadNum = counter.getAndIncrement(); serial = 0; } File getDir(RegressionParameters params) { String name = "scratch"; if (params.getConcurrency() > 1) name += File.separator + threadNum; if (serial > 0) name += "_" + serial; return params.getWorkDirectory().getFile(name); } File getNextDir(RegressionParameters params) { serial++; return getDir(params); } } private static ThreadLocal threadInfo = new ThreadLocal<>() { @Override public ThreadInfo initialValue() { return new ThreadInfo(); } }; ThreadSafeScratchDir(RegressionParameters params, TestDescription td) { super(params, td, threadInfo.get().getDir(params)); } @Override void init(PrintWriter log) throws Fault, InterruptedException { try { super.init(log); } catch (Fault e) { useNextDir(); super.init(log); } } @Override void retainFiles(Status status, PrintWriter log) throws InterruptedException, Fault { try { super.retainFiles(status, log); } catch (Fault f) { useNextDir(); throw f; } } private void useNextDir() { dir = threadInfo.get().getNextDir(params); } } /** * Use a test-specific directory as the scratch directory for the test. * This is used in OtherVM mode when we want to retain some or all of the * files from the test's execution, since it avoids the need to move * files from a shared scratch directory to the test result directory. */ static class TestResultScratchDir extends ScratchDirectory { TestResultScratchDir(RegressionParameters params, TestDescription td) { super(params, td, getResultDir(params, td)); } @Override void retainFiles(Status status, PrintWriter log) throws Fault, InterruptedException { // if scratchDir is the same as resultDir, we just need to delete // the files we don't want to keep; the ones we want to keep are // already in the right place. if (params.getRetainStatus().contains(status.getType())) { // all files to be retained; no need to delete any files } else { Pattern rp = params.getRetainFilesPattern(); if (rp != null) { // delete files which do not match pattern // extend pattern so as not to delete *.jtr files Pattern rp_jtr = Pattern.compile(".*\\.jtr|" + rp.pattern()); deleteFiles(dir, rp_jtr, false, log); } else { // test result doesn't match status set, no patterns specified: // delete all except *.jtr files Pattern jtr = Pattern.compile(".*\\.jtr"); deleteFiles(dir, jtr, false, log); } } } } } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/exec/ShellAction.java000066400000000000000000000377341461415321300301670ustar00rootroot00000000000000/* * Copyright (c) 1998, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.exec; import java.io.File; import java.io.PrintWriter; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; import com.sun.javatest.Status; import com.sun.javatest.regtest.TimeoutHandler; import com.sun.javatest.regtest.config.Locations; import com.sun.javatest.regtest.config.Modules; import com.sun.javatest.regtest.config.OS; import com.sun.javatest.regtest.config.ParseException; import com.sun.javatest.regtest.util.StringUtils; import static com.sun.javatest.regtest.RStatus.*; /** * This class implements the "shell" action as described by the JDK tag * specification. * * @see Action */ public class ShellAction extends Action { public static final String NAME = "shell"; /** * {@inheritDoc} * @return "shell" */ @Override public String getName() { return NAME; } /** * This method does initial processing of the options and arguments for the * action. Processing is determined by the requirements of run(). * * Verify arguments are of length 0. * * Verify that the options are valid for the "shell" action and separate the * shell filename from the shell arguments. * * @param opts The options for the action. * @param args The arguments for the actions. * @param reason Indication of why this action was invoked. * @param script The script. * @exception ParseException If the options or arguments are not expected * for the action or are improperly formated. */ @Override public void init(Map opts, List args, String reason, RegressionScript script) throws ParseException { super.init(opts, args, reason, script); if (args.isEmpty()) throw new ParseException(SHELL_NO_SCRIPT_NAME); for (Map.Entry e: opts.entrySet()) { String optName = e.getKey(); String optValue = e.getValue(); switch (optName) { case "fail": reverseStatus = parseFail(optValue); break; case "timeout": timeout = parseTimeout(optValue); break; case "manual": manual = parseShellManual(optValue); break; default: throw new ParseException(SHELL_BAD_OPTION + optName); } } if (manual.equals("unset")) { if (timeout < 0) timeout = script.getActionTimeout(-1); } else { if (timeout >= 0) // can't have both timeout and manual throw new ParseException(PARSE_TIMEOUT_MANUAL); timeout = 0; } // the first argument is the name of the shell script, the rest are // arguments to the shell script shellFN = args.get(0); //shellArgs = ""; // shellArgs = new ArrayList(); // for (int i = 1; i < args.length; i++) { // //shellArgs += " " + args[i]; // shellArgs.add(args[i]); // } // support simple unescaped ' characters, // as in: @run shell test.sh abc 'def ghi jkl' mno shellArgs = new ArrayList<>(); StringBuilder curr = null; for (int i = 1; i < args.size(); i++) { if (curr == null) curr = new StringBuilder(args.get(i)); else curr.append(" ").append(args.get(i)); if (isEvenQuotes(curr)) { shellArgs.add(curr.toString().replace("'", "")); curr = null; } } if (curr != null) shellArgs.add(curr.toString()); } // init() // where private static boolean isEvenQuotes(StringBuilder s) { int n = 0; for (int i = 0; i < s.length(); i++) { if (s.charAt(i) == '\'') n++; } return (n % 2 == 0); } @Override public Set getSourceFiles() { return Set.of(script.absTestSrcDir().resolve(shellFN).toFile()); } /** * The method that does the work of the action. The necessary work for the * given action is defined by the tag specification. * * Invoke the Bourne shell to run the shell filename with the provided * arguments. The shell filename is fully qualified as necessary and all * environment variables are set according to the tag specification. * * A "shell" action passes if the script exits with an exit code of 0. It * fails otherwise. * * Note that this action inherently assumes that the JVM supports multiple * processes. * * @return The result of the action. * @exception TestRunException If an unexpected error occurs while running * the test. */ @Override public Status run() throws TestRunException { Status status; startAction(false); File shellFile = script.absTestSrcDir().resolve(shellFN).toFile(); if (!shellFile.exists()) throw new TestRunException(CANT_FIND_SRC + shellFile); // If we're only running checks on the contents of the test description // and we got this far, we can just set a successful status. Everything // after this point is preparation to run the actual test. if (script.isCheck()) { status = passed(CHECK_PASS); } else { mkdirs(script.absTestClsDir().toFile()); // CONSTRUCT THE COMMAND LINE // TAG-SPEC: "The source, class, and Java home directories are made // available to shell-action scripts via the environment variables // TESTSRC, TESTCLASSES, and TESTJAVA." Map env = new LinkedHashMap<>(); env.putAll(getEnvVars(true)); Locations locations = script.locations; env.put("TESTFILE", fixupSep(locations.absTestFile())); env.put("TESTSRC", fixupSep(locations.absTestSrcDir())); env.put("TESTSRCPATH", fixupSep(locations.absTestSrcPath())); env.put("TESTCLASSES" , fixupSep(locations.absTestClsDir())); env.put("TESTCLASSPATH", fixupSep(locations.absTestClsPath())); env.put("COMPILEJAVA", fixupSep(script.getCompileJDK().getAbsolutePath())); env.put("TESTJAVA", fixupSep(script.getTestJDK().getAbsolutePath())); List vmOpts = script.getTestVMOptions(); env.put("TESTVMOPTS", fixupSep(StringUtils.join(vmOpts, " "))); List toolVMOpts = script.getTestToolVMOptions(); env.put("TESTTOOLVMOPTS", fixupSep(StringUtils.join(toolVMOpts, " "))); List compilerOpts = script.getTestCompilerOptions(); env.put("TESTJAVACOPTS", fixupSep(StringUtils.join(compilerOpts, " "))); List javaOpts = script.getTestJavaOptions(); env.put("TESTJAVAOPTS", fixupSep(StringUtils.join(javaOpts, " "))); env.put("TESTTIMEOUTFACTOR", String.valueOf(script.getTimeoutFactor())); env.put("TESTROOT", script.getTestRootDir().getPath()); Modules modules = script.getModules(); if (!modules.isEmpty()) env.put("TESTMODULES", modules.toString()); Path nativeDir = script.getNativeDir(); if (nativeDir != null) { env.put("TESTNATIVEPATH", nativeDir.toAbsolutePath().toString()); } if (script.enablePreview()) { env.put("TESTENABLEPREVIEW", "true"); } String testQuery = script.getTestQuery(); if (testQuery != null) { env.put("TESTQUERY", testQuery); } List command = new ArrayList<>(); if (script.useWindowsSubsystemForLinux()) { Path java_exe = script.getTestJDK().getHomeDirectory().resolve("bin").resolve("java.exe"); env.put("NULL", "/dev/null"); if (Files.exists(java_exe)) { // invoking a Windows binary: use standard Windows separator characters env.put("EXE_SUFFIX", ".exe"); env.put("FS", "/"); env.put("PS", File.pathSeparator); env.put("WSLENV", getWSLENV(env, true)); } else { // invoking a Linux binary: use Linux separator characters env.put("FS", "/"); env.put("PS", ";"); env.put("WSLENV", getWSLENV(env, false)); } command.add("wsl.exe"); command.add("sh"); command.add(getWSLPath(shellFile)); } else { // Set up default values for env vars; then override as needed String FS = File.separator; String PS = File.pathSeparator; String NULL = "/dev/null"; if (OS.current().family.equals("windows")) { if (System.getenv("PATH").contains("/cygwin")) { // override values for Cygwin FS = "/"; } else { // override values for MKS (now mostly unsupported) NULL = "NUL"; } } env.put("FS", FS); env.put("PS", PS); env.put("NULL", NULL); command.add("sh"); command.add(shellFile.getPath()); } command.addAll(shellArgs); // PASS TO PROCESSCOMMAND PrintWriter sysOut = section.createOutput("System.out"); PrintWriter sysErr = section.createOutput("System.err"); Lock lock = script.getLockIfRequired(); if (lock != null) lock.lock(); try { if (showCmd) showCmd("shell", command, section); recorder.exec(command, env); TimeoutHandler timeoutHandler = script.getTimeoutHandlerProvider().createHandler(this.getClass(), script, section); // RUN THE SHELL SCRIPT ProcessCommand cmd = new ProcessCommand() .setExecDir(script.absTestScratchDir().toFile()) .setCommand(command) .setEnvironment(env) .setStreams(sysOut, sysErr) .setTimeout(timeout, TimeUnit.SECONDS) .setTimeoutHandler(timeoutHandler); status = normalize(cmd.exec()); } finally { if (lock != null) lock.unlock(); if (sysOut != null) sysOut.close(); if (sysErr != null) sysErr.close(); } // EVALUATE RESULTS if (!status.isError()) { boolean ok = status.isPassed(); int st = status.getType(); String sr; if (ok && reverseStatus) { sr = EXEC_PASS_UNEXPECT; st = Status.FAILED; } else if (ok && !reverseStatus) { sr = EXEC_PASS; } else if (!ok && reverseStatus) { sr = EXEC_FAIL_EXPECT; st = Status.PASSED; } else { /* !ok && !reverseStatus */ sr = EXEC_FAIL; } if ((st == Status.FAILED) && !status.getReason().equals("") && !status.getReason().equals(EXEC_PASS)) sr += ": " + status.getReason(); status = createStatus(st, sr); } } endAction(status); return status; } // run() // where private String fixupSep(List files) { StringBuilder sb = new StringBuilder(); for (Path f: files) { if (sb.length() > 0) sb.append(File.pathSeparator); sb.append(fixupSep(f)); } return sb.toString(); } private String fixupSep(Path f) { return fixupSep(f.toString()); } private String fixupSep(File f) { return fixupSep(f.getPath()); } private String fixupSep(String s) { return (sep == null ? s : s.replace(File.separator, sep)); } private static final String sep = getSeparator(); private static String getSeparator() { return (File.separatorChar == '\\' ? System.getProperty("javatest.shell.separator", "/") : null); } private String parseShellManual(String value) throws ParseException { if (value != null) throw new ParseException(SHELL_MANUAL_NO_VAL + value); else value = "novalue"; return value; } // parseShellManual() private String getWSLENV(Map env, boolean targetIsWindows) { StringBuilder sb = new StringBuilder(); String sep = ""; for (String name : env.keySet()) { String suffix; switch (name) { case "COMPILEJAVA": case "TESTJAVA": case "TESTROOT": suffix = "/p"; break; case "TESTSRC": case "TESTCLASSES": suffix = targetIsWindows ? "" : "/p"; break; case "TESTSRCPATH": case "TESTCLASSPATH": case "TESTNATIVEPATH": suffix = targetIsWindows ? "" : "/l"; break; default: if (name.equalsIgnoreCase("PATH")) { continue; } suffix = ""; } sb.append(sep).append(name).append(suffix); sep = ":"; } return sb.toString(); } private String getWSLPath(File file) { Path path = file.toPath().toAbsolutePath(); char driveLetter = Character.toLowerCase(path.getRoot().toString().charAt(0)); StringBuilder result = new StringBuilder(); result.append("/mnt/").append(driveLetter); for (Path pathElement : path) { result.append("/").append(pathElement); } return result.toString(); } //----------member variables------------------------------------------------ private String shellFN; private List shellArgs; private boolean reverseStatus = false; private int timeout = -1; private String manual = "unset"; // or "novalue" } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/exec/TestNGAction.java000066400000000000000000000153551461415321300302570ustar00rootroot00000000000000/* * Copyright (c) 2012, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.exec; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import com.sun.javatest.Status; import com.sun.javatest.regtest.agent.JDK_Version; import com.sun.javatest.regtest.agent.TestNGRunner; import com.sun.javatest.regtest.config.Locations; import com.sun.javatest.regtest.config.Locations.LibLocn; import com.sun.javatest.regtest.config.ParseException; import com.sun.javatest.regtest.util.FileUtils; /** * This class implements the implicit "testng" action for TestNG tests. * * @see Action */ public class TestNGAction extends MainAction { public static final String NAME = "testng"; /** * {@inheritDoc} * @return "testng" */ @Override public String getName() { return NAME; } /** * This method does initial processing of the options and arguments for the * action. Processing is determined by the requirements of run(). * * Verify arguments are not of length 0 and separate them into the options * to java, the classname, and the parameters to the named class. * * Verify that the options are valid for the "testng" action. * * @param opts The options for the action. * @param args The arguments for the actions. * @param reason Indication of why this action was invoked. * @param script The script. * @exception ParseException If the options or arguments are not expected * for the action or are improperly formatted. */ @Override public void init(Map opts, List args, String reason, RegressionScript script) throws ParseException { userSpecified = reason.startsWith(SREASON_USER_SPECIFIED); boolean importsJUnit = (script.getTestDescription().getParameter("importsJUnit") != null); init(opts, args, reason, script, TestNGRunner.class, script.getTestResult().getTestName(), Boolean.toString(importsJUnit)); if (importsJUnit) { othervmOverrideReasons.add("test uses TestNG/JUnit mixed mode"); } } // init() boolean userSpecified = false; // cache results? @Override protected Status build() throws TestRunException { if (userSpecified) { return super.build(); } else { JDK_Version v = script.getCompileJDKVersion(); Map buildOpts = new HashMap<>(); if (v.compareTo(JDK_Version.V1_6) >= 0) { buildOpts.put("implicit", "none"); } Locations locations = script.locations; Set buildArgs = new LinkedHashSet<>(script.getLibBuildArgs()); if (buildArgs.isEmpty()) { buildArgs.addAll(listModules(locations.absLibSrcList(LibLocn.Kind.SYS_MODULE))); buildArgs.addAll(listModules(locations.absLibSrcList(LibLocn.Kind.USER_MODULE))); buildArgs.addAll(listClasses(locations.absLibSrcList(LibLocn.Kind.PACKAGE))); } try { Path testSrcDir = locations.absTestSrcDir(); switch (locations.getDirKind(testSrcDir)) { case PACKAGE: buildArgs.addAll(listClasses(List.of(testSrcDir))); break; case SYS_MODULE: case USER_MODULE: buildArgs.addAll(listModules(List.of(testSrcDir))); break; } } catch (Locations.Fault e) { return Status.error(e.getMessage()); } BuildAction ba = new BuildAction(); return ba.build(buildOpts, new ArrayList<>(buildArgs), SREASON_ASSUMED_BUILD, script); } } private List listClasses(List roots) { List classes = new ArrayList<>(); for (Path root: roots) listClasses(root, null, classes); return classes; } private void listClasses(Path dir, String pkg, List classes) { // candidate for Files.walkFileTree for (Path f : FileUtils.listFiles(dir)) { String f_name = f.getFileName().toString(); if (Files.isDirectory(f)) { listClasses(f, pkg == null ? f_name : pkg + "." + f_name, classes); } else if (f_name.endsWith(".java")) { String c_name = f_name.substring(0, f_name.length() - 5); classes.add(pkg == null ? c_name : pkg + "." + c_name); } } } private Set listModules(List roots) { Set modules = new LinkedHashSet<>(); for (Path root: roots) { for (Path f : FileUtils.listFiles(root)) { if (Files.isDirectory(f)) { modules.add(f.getFileName() + "/*"); } } } return modules; } private static final Path TESTNG_RESULTS_XML = Path.of("testng-results.xml"); @Override public void endAction(Status s) { super.endAction(s); if (script.isCheck()) return; script.getTestNGSummaryReporter().add(script.getTestResult(), section); String jtrPath = script.getTestResult().getWorkRelativePath(); String tngPath = jtrPath.replaceAll("\\.jtr$", ".testng-results.xml"); script.saveScratchFile(TESTNG_RESULTS_XML, Path.of(tngPath)); } } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/exec/TestRunException.java000066400000000000000000000033411461415321300312300ustar00rootroot00000000000000/* * Copyright (c) 1998, 2016, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.exec; /** * This class defines any exception thrown by the Regression extensions. */ public class TestRunException extends Exception { private static final long serialVersionUID = 6404240514286146053L; public TestRunException(String msg) { super(msg); } // TestRunException() public TestRunException(String msg, Throwable t) { super(msg, t); } // TestRunException() public TestRunException(Throwable t) { super(t.getMessage(), t); } // TestRunException() } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/exec/TimeoutHandlerProvider.java000066400000000000000000000116341461415321300324100ustar00rootroot00000000000000/* * Copyright (c) 2014, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.exec; import com.sun.javatest.regtest.TimeoutHandler; import com.sun.javatest.TestResult.Section; import java.io.File; import java.io.PrintWriter; import java.lang.reflect.Constructor; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.nio.file.Path; import java.util.List; /** * This class keeps track of which TimeoutHandler implementation to use * and will create instances thereof. */ public class TimeoutHandlerProvider { private String className; private ClassLoader loader; private static final long defaultTimeout = 300; // seconds private long timeout = defaultTimeout; /** * Set the class name of the TimeoutHandler sub-class. * @param name the class name */ public void setClassName(String name) { className = name; } /** * Set the class path for loading the timeout handler. * @param path the class path * @throws java.net.MalformedURLException if any of the files on the path cannot be converted * to a URL */ public void setClassPath(List path) throws MalformedURLException { URL[] urls = new URL[path.size()]; int u = 0; for (Path f: path) { urls[u++] = f.toUri().toURL(); } loader = new URLClassLoader(urls); } /** * Load the class specified by setClassName and setClassPath. * @return the class * @throws ClassNotFoundException if the class cannot be found */ private Class loadClass() throws ClassNotFoundException { Class handlerClass; if (loader == null) { handlerClass = Class.forName(className); } else { handlerClass = Class.forName(className, true, loader); } return handlerClass.asSubclass(TimeoutHandler.class); } /** * Create an instance of the {@code TimeoutHandler} that has been configured. * @param actionClass the class of the action * @param script the script with which the timeout handler will be associated * @param section the section in the scripts test rult object in which to write messages * @return the object */ public TimeoutHandler createHandler(Class actionClass, RegressionScript script, Section section) { PrintWriter log = section.getMessageWriter(); File outDir = script.absTestScratchDir().toFile(); Path testJDK = script.getTestJDK().getAbsoluteHomeDirectory(); if (className != null) { try { Class clz = loadClass(); Constructor ctor = clz.getDeclaredConstructor(PrintWriter.class, File.class, File.class); TimeoutHandler th = ctor.newInstance(log, outDir, testJDK.toFile()); th.setTimeout(timeout); return th; } catch (Exception ex) { log.println("Failed to instantiate timeout handler: " + className); ex.printStackTrace(log); log.println("Reverting to the default timeout handler."); } } // DefaultTimeoutHandler does not support shell actions if (actionClass == ShellAction.class) { return null; } return new DefaultTimeoutHandler(log, outDir, testJDK); } /** * Set the timeout for the timeout handler. * -1: default timeout; 0: no timeout; >0: timeout in seconds * @param timeout a timeout in seconds */ public void setTimeout(long timeout) { this.timeout = (timeout == -1) ? defaultTimeout : timeout; } public long getTimeout() { return timeout; } } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/exec/package-info.java000066400000000000000000000036541461415321300303000ustar00rootroot00000000000000/* * Copyright (c) 2016, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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. */ /** * Provides support classes for the JDK Regression Test Harness, jtreg, * for executing individual tests. * *

* The primary class in this package is {@link RegressionScript}. * An instance of {@code RegressionScript} is created for each test * to be run. It analyzes the action tags in the test description * and creates a series of {@link Action} objects, using appropriate * subtypes, {@link BuildAction}, {@link CompileAction}, {@link MainAction}, * and so forth. * *

This is NOT part of any supported API. * If you write code that depends on this, you do so at your own risk. * This code and its internal interfaces are subject to change or * deletion without notice. */ package com.sun.javatest.regtest.exec; jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/package-info.java000066400000000000000000000024511461415321300273460ustar00rootroot00000000000000/* * Copyright (c) 2016, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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. */ /** * Provides public API for the Regression Test Harness for JDK: jtreg. */ package com.sun.javatest.regtest; jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/report/000077500000000000000000000000001461415321300254705ustar00rootroot00000000000000jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/report/BasicObserver.java000066400000000000000000000040641461415321300310700ustar00rootroot00000000000000/* * Copyright (c) 2011, 2016, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.report; import com.sun.javatest.Harness; import com.sun.javatest.Parameters; import com.sun.javatest.TestResult; /** * Empty impl for convenience of subtypes */ public class BasicObserver implements Harness.Observer { /** {@inheritDoc} */ @Override public void startingTestRun(Parameters params) { } /** {@inheritDoc} */ @Override public void startingTest(TestResult tr) { } /** {@inheritDoc} */ @Override public void finishedTest(TestResult tr) { } /** {@inheritDoc} */ @Override public void stoppingTestRun() { } /** {@inheritDoc} */ @Override @SuppressWarnings("deprecation") public void finishedTesting() { } /** {@inheritDoc} */ @Override public void finishedTestRun(boolean ok) { } /** {@inheritDoc} */ @Override public void error(String string) { } } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/report/ElapsedTimeHandler.java000066400000000000000000000131011461415321300320210ustar00rootroot00000000000000/* * Copyright (c) 2011, 2016, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.report; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.Writer; import java.util.Map; import java.util.TreeMap; import java.util.WeakHashMap; import com.sun.javatest.Harness; import com.sun.javatest.Parameters; import com.sun.javatest.TestResult; import com.sun.javatest.report.Report; /** * Monitor the elapsed times of tests using a Harness.Observer and write a * summary to a file. */ public class ElapsedTimeHandler { public ElapsedTimeHandler() { this(1); } public ElapsedTimeHandler(int resolution) { this.resolution = resolution; table = new Table(resolution); } public void register(Harness h) { h.addObserver(new BasicObserver() { @Override public void startingTestRun(Parameters p) { startTimes = new WeakHashMap<>(); } @Override public synchronized void startingTest(TestResult tr) { startTimes.put(tr, System.currentTimeMillis()); } @Override public synchronized void finishedTest(TestResult tr) { Long start = startTimes.remove(tr); if (start == null) return; table.record(start, System.currentTimeMillis()); } @Override public void stoppingTestRun() { startTimes = null; } private Map startTimes; }); } public void report(Report report) throws IOException { File reportDir = report.getReportDir(); File reportTextDir = new File(reportDir, "text"); reportTextDir.mkdirs(); File file = new File(reportTextDir, "timeStats.txt"); report(file); } public void report(File file) throws IOException { try (Writer out = new BufferedWriter(new FileWriter(file))) { if (resolution == 1) out.write(String.format("%5s,%5s%n", "time", "count")); else out.write(String.format("%5s,%5s,%5s", "time", "blk", "count")); for (Map.Entry e: table.entrySet()) { int k = e.getKey(); int v = e.getValue(); if (resolution == 1) out.write(String.format("%5d,%5d%n", k, v)); else out.write(String.format("%5d,%5d,%5d%n", k*resolution, k, v)); } out.write(String.format("%n")); out.write(String.format("Mean %6.2fs%n", table.getMean()* resolution)); out.write(String.format("Standard deviation %6.2fs%n", table.getStdDev() * resolution)); int e = table.getElapsedTime(); int mins = e / 60; int secs = e % 60; out.write(String.format("Total elapsed time %dm %ds%n", mins, secs)); } } private int resolution; private Table table; class Table extends TreeMap { private static final long serialVersionUID = 0; Table(int resolution) { this.resolution = resolution; } void record(long start, long end) { if (earliest == 0 || start < earliest) earliest = start; if (latest == 0 || end > latest) latest = end; int elapsed = (int) ((end - start) / 1000); int bucket = (elapsed / resolution); inc(bucket); } void inc(int bucket) { Integer value = get(bucket); put(bucket, (value == null) ? 1 : value + 1); count++; total += bucket; totalSquares += (bucket * bucket); } double getMean() { return total / count; } double getStdDev() { double mean = total / count; return Math.sqrt(totalSquares / count - mean * mean); } int getElapsedTime() { if (earliest == 0 && latest == 0) return 0; if (earliest == 0 || latest == 0) throw new IllegalStateException(); return (int) ((latest - earliest) / 1000); } int resolution; int count; double total; double totalSquares; long earliest; long latest; } } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/report/RegressionReporter.java000066400000000000000000000500431461415321300322000ustar00rootroot00000000000000/* * Copyright (c) 2011, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.report; import java.io.BufferedWriter; import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.text.DateFormat; import java.util.Date; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import com.sun.javatest.TestFilter; import com.sun.javatest.regtest.Main.Fault; import com.sun.javatest.regtest.config.RegressionParameters; import com.sun.javatest.regtest.config.RegressionTestSuite; import com.sun.javatest.regtest.config.TestManager; import com.sun.javatest.report.Report; import com.sun.javatest.report.ReportSettings; import com.sun.javatest.util.HTMLWriter; /** * Handles the generation of reports for test runs. * For an individual test run, it uses the basic JT Harness support for * writing reports. * For a multi-run, it generates the top level combined report directly. */ public class RegressionReporter { public RegressionReporter(PrintWriter log) { this.log = log; } public void report(RegressionParameters params, ElapsedTimeHandler elapsedTimeHandler, TestStats testStats, TestFilter filter, boolean quiet) { File rd = params.getReportDir().toFile(); File wd = params.getWorkDirectory().getRoot(); try { if (Thread.interrupted()) { // It is important to ensure the interrupted bit is cleared before writing // a report, because Report.writeReport checks if the interrupted bit is set, // and will stop writing the report. This typically manifests itself as // writing the HTML files but /not/ writing the text/summary.txt file. log.println("WARNING: interrupt status cleared prior to writing report"); } Report r = new Report(); ReportSettings s = new ReportSettings(params); if (reportKinds.contains("html")) { s.setEnableHtmlReport(true); s.setHtmlMainReport(true, true); s.setShowKflReport(false); } if (reportKinds.contains("text")) { s.setEnablePlainReport(true); } if (reportKinds.contains("xml")) { s.setEnableXmlReport(true); } s.setFilter(filter); if (backups == null) s.setEnableBackups(false); else { try { s.setBackupLevels(Integer.parseInt(backups)); s.setEnableBackups(true); } catch (NumberFormatException e) { // ignore } } rd.mkdirs(); r.writeReports(s, rd); if (s.isPlainEnabled()) { if (elapsedTimeHandler != null) elapsedTimeHandler.report(r); if (testStats != null) testStats.report(r); for (var sr : List.of( SummaryReporter.forTestNG(params.getWorkDirectory()), SummaryReporter.forJUnit(params.getWorkDirectory()))) { if (!sr.isEmpty()) { sr.writeReport(rd); } } } fixupReports(rd, wd); if (!quiet) logReportWritten(rd); } catch (IOException | SecurityException e) { log.println("Error while writing report: " + e); } } public void report(TestManager testManager) throws Fault { this.testManager = testManager; this.reportDir = testManager.getReportDirectory().toFile(); parent = getCommonParent(testManager.getTestSuites()); // ignore the case where the common parent is just the root directory if (parent != null && parent.getParentFile() == null) parent = null; try { if (reportKinds.contains("html")) writeHTMLReport(); if (reportKinds.contains("text")) { writeCombinedSummary(); // for extra marks, write a combined elapsedTime file } writeIndex(); fixupReports(reportDir, testManager.getWorkDirectory().toFile()); logReportWritten(reportDir); } catch (IOException e) { log.println("Error while writing report: " + e); } } private void logReportWritten(File reportDir) { File report = new File(new File(reportDir, "html"), "report.html"); if (report.exists()) log.println("Report written to " + canon(report)); } /** * Create html/index.html that links to the subdir data. * The page is a simple table containing rows * testsuite (link to work subdir) (link to report subdir) */ private void writeHTMLReport() throws IOException, Fault { String title = (parent == null) ? "MultiRun Report" : "MultiRun Report: " + parent; File htmlDir = new File(reportDir, "html"); htmlDir.mkdirs(); File report = new File(htmlDir, "report.html"); try (BufferedWriter htmlOut = new BufferedWriter(new FileWriter(report))) { HTMLWriter html = new HTMLWriter(htmlOut); html.startTag(HTMLWriter.HTML); html.startTag(HTMLWriter.HEAD); html.startTag(HTMLWriter.TITLE); html.write(title); html.endTag(HTMLWriter.TITLE); html.endTag(HTMLWriter.HEAD); html.startTag(HTMLWriter.BODY); html.startTag(HTMLWriter.H1); html.write(title); html.endTag(HTMLWriter.H1); html.startTag(HTMLWriter.P); html.write("Date of report: " + df.format(new Date())); html.endTag(HTMLWriter.P); html.startTag(HTMLWriter.TABLE); html.writeAttr(HTMLWriter.BORDER, "1"); html.startTag(HTMLWriter.TR); for (String s: new String[] { "Test Suite", "Results", "Report" }) { html.startTag(HTMLWriter.TH); html.write(s); html.endTag(HTMLWriter.TH); } html.endTag(HTMLWriter.TR); for (RegressionTestSuite testSuite: testManager.getTestSuites()) { html.startTag(HTMLWriter.TR); html.startTag(HTMLWriter.TD); html.startTag(HTMLWriter.A); File ts = testSuite.getRootDir(); html.writeAttr(HTMLWriter.HREF, getURIPath(ts)); html.write(relativize(parent, ts).getPath()); html.endTag(HTMLWriter.A); html.endTag(HTMLWriter.TD); html.startTag(HTMLWriter.TD); html.startTag(HTMLWriter.A); File wd = testManager.getWorkDirectory(testSuite).getRoot(); html.writeAttr(HTMLWriter.HREF, getURIPath(wd)); html.write(wd.getName()); html.endTag(HTMLWriter.A); html.endTag(HTMLWriter.TD); html.startTag(HTMLWriter.TD); html.startTag(HTMLWriter.A); Path rd = testManager.getReportDirectory(testSuite); html.writeAttr(HTMLWriter.HREF, "../" + encode(rd.getFileName().toString()) + "/index.html"); html.write(rd.getFileName().toString()); html.endTag(HTMLWriter.A); html.endTag(HTMLWriter.TD); html.endTag(HTMLWriter.TR); } html.endTag(HTMLWriter.TABLE); html.endTag(HTMLWriter.BODY); html.endTag(HTMLWriter.HTML); html.close(); } } /* If the work dir and report dir are equal or close to each other in the * file system, rewrite HTML files in the report directory, replacing * absolute paths for the work directory with relative paths. */ private void fixupReports(File report, File work) throws IOException { // ensure all files normalized work = getCanonicalFile(work); report = getCanonicalFile(report); File workParent = work.getParentFile(); File reportParent = report.getParentFile(); File htmlDir = new File(report, "html"); if (equal(work, report)) { fixupReportFiles(report, work, "."); fixupReportFiles(htmlDir, work, ".."); } else if (equal(report, workParent)) { String relPath = encode(work.getName()); fixupReportFiles(report, work, relPath); fixupReportFiles(htmlDir, work, "../" + relPath); } else if (equal(work, reportParent)) { fixupReportFiles(report, work, ".."); fixupReportFiles(htmlDir, work, "../.."); } else if (equal(workParent, reportParent)) { String relPath = encode(work.getName()); fixupReportFiles(report, work, "../" + relPath); fixupReportFiles(htmlDir, work, "../../" + relPath); } else if (equal(workParent.getParentFile(), reportParent.getParentFile())) { // This case is notable for multi-run jobs String relPath = "../../" + encode(workParent.getName()) + "/" + encode(work.getName()); fixupReportFiles(report, work, relPath); fixupReportFiles(htmlDir, work, "../" + relPath); } } /** * Returns the URL encoding of a string. */ private String encode(String s) throws IOException { return URLEncoder.encode(s, StandardCharsets.UTF_8); } /* Rewrite html files in the given directory, replacing hrefs to the old path * with references to the new path. * Since all files have been canonicalized, we should not need to worry * about inconsistent case on case-equivalent file systems like Mac and Windows. */ private void fixupReportFiles(File dir, File oldFile, String newPath) throws IOException { /* * For compatibility, we detect and replace the form of the URL as * encoded by JT Harness 5.0, and the anticipated form, generated by * using file.toURI().getRawPath(). */ Map replaceMap = new LinkedHashMap<>(); replaceMap.put("href=\"" + getURIPath(oldFile) + "/", "href=\"" + newPath + "/"); replaceMap.put("href=\"" + getURIPath(oldFile) + "\"", "href=\"" + newPath + "\""); replaceMap.put("href=\"" + getCanonicalURIPath(oldFile) + "/", "href=\"" + newPath + "/"); replaceMap.put("href=\"" + getCanonicalURIPath(oldFile) + "\"", "href=\"" + newPath + "\""); replaceMap.put("href=\"" + getURIPath(dir) + "/", "href=\""); replaceMap.put("href=\"" + getURIPath(dir) + "\"", "href=\".\""); replaceMap.put("href=\"" + getCanonicalURIPath(dir) + "/", "href=\""); replaceMap.put("href=\"" + getCanonicalURIPath(dir) + "\"", "href=\".\""); // Additional fixup to workaround bugs replaceMap.put("href=\"#Configuration and Other Settings\"", "href=\"#Configuration%20and%20Other%20Settings\""); replaceMap.put("href=\"#Known Failure Analysis\"", "href=\"#Known%20Failure%20Analysis\""); // System.err.println("fixUpReportFiles " + dir); // for (Map.Entry e : replaceMap.entrySet()) { // System.err.println(" replace: " + e.getKey()); // System.err.println(" with: " + e.getValue()); // } File[] children = dir.listFiles(); if (children == null) { log.println("Cannot update report files for " + dir); } else { for (File f: children) { if (f.getName().endsWith(".html")) { try { String content = read(f); for (Map.Entry e : replaceMap.entrySet()) { content = content.replace(e.getKey(), e.getValue()); } write(f, content); } catch (IOException e) { log.println("Error while updating report: " + e); } } } } } /** * Returns the URL-encoded form of a file, with any trailing '/' removed. */ String getURIPath(File f) { String p = f.toURI().getRawPath(); return p.endsWith("/") ? p.substring(0, p.length() - 1) : p; } // This method mimics the code in JTHarness class com.sun.javatest.util.HtmlWriter, // method writeLink, which writes out absolute files as URI paths. String getCanonicalURIPath(File f) throws IOException { File cf = getCanonicalFile(f); StringBuilder sb = new StringBuilder(); String path = cf.getPath(); if (cf.isAbsolute() && !path.startsWith("/")) sb.append('/'); for (int i = 0; i < path.length(); i++) { char ch = path.charAt(i); String encoded = (ch == File.separatorChar) ? "/" : URLEncoder.encode(String.valueOf(ch), StandardCharsets.UTF_8); sb.append(encoded); } return sb.toString(); } File getCanonicalFile(File f) { try { return f.getCanonicalFile(); } catch (IOException e) { return f.getAbsoluteFile(); } } private void writeCombinedSummary() throws IOException, Fault { File textDir = new File(reportDir, "text"); textDir.mkdirs(); File report = new File(textDir, "summary.txt"); try (BufferedWriter summaryOut = new BufferedWriter(new FileWriter(report))) { for (RegressionTestSuite ts: testManager.getTestSuites()) { Path f = testManager.getReportDirectory(ts).resolve("text").resolve("summary.txt"); if (Files.exists(f)) { String s = Files.readString(f); if (!s.endsWith("\n")) s += "\n"; summaryOut.write(s); } } } } private void writeIndex() throws IOException { String title = (parent == null) ? "MultiRun Report" : "MultiRun Report: " + parent; File index = new File(reportDir, "index.html"); try (BufferedWriter indexOut = new BufferedWriter(new FileWriter(index))) { HTMLWriter html = new HTMLWriter(indexOut); html.startTag(HTMLWriter.HTML); html.startTag(HTMLWriter.HEAD); html.startTag(HTMLWriter.TITLE); html.write(title); html.endTag(HTMLWriter.TITLE); html.endTag(HTMLWriter.HEAD); html.startTag(HTMLWriter.BODY); html.startTag(HTMLWriter.H1); html.write(title); html.endTag(HTMLWriter.H1); html.startTag(HTMLWriter.P); html.write("Date of report: " + df.format(new Date())); html.endTag(HTMLWriter.P); if (reportKinds.contains("html")) { html.startTag(HTMLWriter.P); html.startTag(HTMLWriter.A); html.writeAttr(HTMLWriter.HREF, "html/report.html"); html.write("HTML Report"); html.endTag(HTMLWriter.A); html.startTag(HTMLWriter.BR); html.write("Contains links to the reports for the tests grouped by test suite."); html.endTag(HTMLWriter.P); } if (reportKinds.contains("text")) { html.startTag(HTMLWriter.P); html.startTag(HTMLWriter.A); html.writeAttr(HTMLWriter.HREF, "text/summary.txt"); html.write("Plain Text Report"); html.endTag(HTMLWriter.A); html.startTag(HTMLWriter.BR); html.write("Combined text report for all the tests."); html.endTag(HTMLWriter.P); } html.endTag(HTMLWriter.BODY); html.endTag(HTMLWriter.HTML); } } private String read(File f) throws IOException { byte[] bytes = new byte[(int) f.length()]; try (DataInputStream fIn = new DataInputStream(new FileInputStream(f))) { fIn.readFully(bytes); return new String(bytes); } } private void write(File f, String s) throws IOException { try (FileOutputStream fOut = new FileOutputStream(f)) { fOut.write(s.getBytes()); } } private static File getCommonParent(Set testSuites) { String FS = File.separator; String path = null; for (RegressionTestSuite testSuite: testSuites) { File file = testSuite.getRootDir(); File dir = file.isDirectory() ? file : file.getParentFile(); File absDir = (dir == null) ? new File(System.getProperty("user.dir")) : dir.getAbsoluteFile(); String p = absDir.getPath(); if (!p.endsWith(FS)) p += FS; if (path == null || path.startsWith(p)) path = p; else if (!p.startsWith(path)) { int i = -1; while (true) { int next = path.indexOf(FS, i + 1); if (next == -1 || next >= p.length() || !p.substring(i + 1, next).equals(path.substring(i + 1, next))) break; i = next; } if (i == -1) return null; path = path.substring(0, i + 1); } } return (path == null ? null : new File(path)); } private static File relativize(File base, File f) { if (base != null) { StringBuilder sb = new StringBuilder(); for ( ; f != null; f = f.getParentFile()) { if (f.equals(base)) return new File(sb.toString()); if (sb.length() > 0) sb.insert(0, File.separator); sb.insert(0, f.getName()); } } return f; } private static File canon(File file) { try { return file.getCanonicalFile(); } catch (IOException e) { return file.getAbsoluteFile(); } } private static boolean equal(T t1, T t2) { return (t1 == null ? t2 == null : t1.equals(t2)); } final PrintWriter log; private File reportDir; private TestManager testManager; private File parent; DateFormat df = DateFormat.getDateTimeInstance(); String backups = System.getProperty("javatest.report.backups"); // default: none List reportKinds = List.of(System.getProperty("javatest.report.kinds", "html text").split("[ ,]+")); } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/report/SummaryReporter.java000066400000000000000000000255331461415321300315230ustar00rootroot00000000000000/* * Copyright (c) 2012, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.report; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.util.HashMap; import java.util.Map; import java.util.TreeMap; import java.util.WeakHashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.sun.javatest.TestDescription; import com.sun.javatest.TestResult; import com.sun.javatest.WorkDirectory; import com.sun.javatest.regtest.agent.ActionHelper.OutputHandler.OutputKind; /** * Class to generate aggregate reports for collections of tests, such as JUnit and TestNG tests. */ public abstract class SummaryReporter { private static final Map, SummaryReporter>> instanceMap = new WeakHashMap<>(); /** * A summary reporter that aggregates info for TestNG tests, using info written * to stdout in each test by TestNG. * * @param wd the work directory for the test run * @return the summary reporter */ public static synchronized SummaryReporter forTestNG(WorkDirectory wd) { return instanceMap.computeIfAbsent(wd, wd_ -> new HashMap<>()) .computeIfAbsent(TestNGSummaryReporter.class, c_ -> new TestNGSummaryReporter()); } /** * A summary reporter that aggregates info for JUnit tests, using info written * to stderr in each test by JUnitRunner, using a SummaryGeneratingListener. * * @param wd the work directory for the test run * @return the summary reporter */ public static synchronized SummaryReporter forJUnit(WorkDirectory wd) { return instanceMap.computeIfAbsent(wd, wd_ -> new HashMap<>()) .computeIfAbsent(JUnitSummaryReporter.class, c_ -> new JUnitSummaryReporter()); } /** * Returns {@code true} if there is no content to be shown. * * @return {@code true} if there is no content to be shown */ public abstract boolean isEmpty(); /** * Adds the results for an action in a test. * * @param tr the test result for the test * @param s the section containing the output for the action */ public abstract void add(TestResult tr, TestResult.Section s); /** * Writes a summary report about the tests that executed. * * @param reportDir the directory in which to write the report * @throws IOException if there is a problem writing the report */ public abstract void writeReport(File reportDir) throws IOException; /** * A summary reporter that aggregates info for TestNG tests, using info written * to stdout in each test by TestNG. */ private static class TestNGSummaryReporter extends SummaryReporter { private final Map infoMap = new TreeMap<>(); @Override public boolean isEmpty() { return infoMap.isEmpty(); } static final String testsPrefix = "Total tests run:"; static final Pattern testsPattern = Pattern.compile("[^0-9]+([0-9]+)[^0-9]+([0-9]+)[^0-9]+([0-9]+)[^0-9]*"); static final String configPrefix = "Configuration Failures:"; static final Pattern configPattern = Pattern.compile("[^0-9]+([0-9]+)[^0-9]+([0-9]+)[^0-9]*"); @Override public synchronized void add(TestResult tr, TestResult.Section s) { try { TestDescription td = tr.getDescription(); String group = td.getParameter("packageRoot"); if (group == null) group = td.getRootRelativePath(); Info info = infoMap.get(group); if (info == null) infoMap.put(group, info = new Info()); String out = s.getOutput(OutputKind.STDOUT.name); if (out != null) { Matcher tm = getMatcher(out, testsPrefix, testsPattern); if (tm != null && tm.matches()) { info.count += Integer.parseInt(tm.group(1)); info.failureCount += Integer.parseInt(tm.group(2)); info.skippedCount += Integer.parseInt(tm.group(3)); } Matcher cm = getMatcher(out, configPrefix, configPattern); if (cm != null && cm.matches()) { info.configFailureCount += Integer.parseInt(cm.group(1)); info.configSkippedCount += Integer.parseInt(cm.group(2)); } } } catch (TestResult.Fault e) { // should not occur with tr still in memory } } private Matcher getMatcher(String out, String prefix, Pattern p) { int pos = out.lastIndexOf(prefix); if (pos == -1) return null; int endPos = out.indexOf("\n", pos); if (endPos == -1) return null; return p.matcher(out.substring(pos, endPos)); } @Override public void writeReport(File reportDir) throws IOException { File reportTextDir = new File(reportDir, "text"); reportTextDir.mkdirs(); File f = new File(reportTextDir, "testng.txt"); try (PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(f)))) { for (Map.Entry e : infoMap.entrySet()) { out.println(e.getKey() + " " + e.getValue()); } } } static class Info { int count; // int successCount; int failureCount; int skippedCount; int configFailureCount; int configSkippedCount; @Override public String toString() { return "total: " + count + ", passed: " + (count - failureCount - skippedCount) + ", failed: " + failureCount + ", skipped: " + skippedCount + ", config failed: " + configFailureCount + ", config skipped: " + configSkippedCount; } } } /** * A summary reporter that aggregates info for JUnit tests, using info written * to stderr in each test by JUnitRunner, using a SummaryGeneratingListener. */ private static class JUnitSummaryReporter extends SummaryReporter { private final Map infoMap = new TreeMap<>(); @Override public boolean isEmpty() { return infoMap.isEmpty(); } static final Pattern infoPattern = Pattern.compile("(?s)\\[ JUnit Containers:.*JUnit Tests:.*]"); static final Pattern numberPattern = Pattern.compile("[0-9]+"); @Override public synchronized void add(TestResult tr, TestResult.Section s) { try { TestDescription td = tr.getDescription(); String group = td.getParameter("packageRoot"); if (group == null) group = td.getRootRelativePath(); Info info = infoMap.computeIfAbsent(group, g -> new Info()); String out = s.getOutput(OutputKind.STDERR.name); if (out != null) { Matcher m1 = infoPattern.matcher(out); if (m1.find()) { Matcher m2 = numberPattern.matcher(m1.group()); info.containers.count += nextInt(m2); info.containers.started += nextInt(m2); info.containers.succeeded += nextInt(m2); info.containers.failed += nextInt(m2); info.containers.aborted += nextInt(m2); info.containers.skipped += nextInt(m2); info.tests.count += nextInt(m2); info.tests.started += nextInt(m2); info.tests.succeeded += nextInt(m2); info.tests.failed += nextInt(m2); info.tests.aborted += nextInt(m2); info.tests.skipped += nextInt(m2); } } } catch (TestResult.Fault e) { // should not occur with tr still in memory } } private int nextInt(Matcher m) { return m.find() ? Integer.parseInt(m.group()) : 0; } @Override public void writeReport(File reportDir) throws IOException { File reportTextDir = new File(reportDir, "text"); reportTextDir.mkdirs(); File f = new File(reportTextDir, "junit.txt"); try (PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(f)))) { for (Map.Entry e: infoMap.entrySet()) { out.println(e.getKey() + " " + e.getValue()); } } } static class Counts { int count; int started; int succeeded; int failed; int aborted; int skipped; public String toString() { return count + ", skipped: " + skipped + ", started: " + started + ", succeeded: " + succeeded + ", failed: " + failed + ", aborted: " + aborted; } } static class Info { final Counts containers = new Counts(); final Counts tests = new Counts(); @Override public String toString() { return "containers: " + containers + "; tests: " + tests; } } } } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/report/TestStats.java000066400000000000000000000233621461415321300302770ustar00rootroot00000000000000/* * Copyright (c) 2011, 2018, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.report; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import com.sun.javatest.Harness; import com.sun.javatest.Parameters; import com.sun.javatest.Status; import com.sun.javatest.TestResult; import com.sun.javatest.regtest.config.CachingTestFilter; import com.sun.javatest.regtest.config.RegressionParameters; import com.sun.javatest.report.Report; import com.sun.javatest.util.I18NResourceBundle; /** * Track test status statistics */ public class TestStats { public void register(Harness h) { // See the comments for RegressionParameters.getExcludeListFilter // for notes regarding the use of CachingTestFilter vs. ObservableTestFilter // for params.getExcludeListFilter. h.addObserver(new BasicObserver() { @Override public void startingTestRun(Parameters params) { this.params = (RegressionParameters) params; } @Override public void finishedTesting() { CachingTestFilter ef = params.getExcludeListFilter(); if (ef != null) { for (CachingTestFilter.Entry e: ef.getCacheEntries()) { if (!e.value) excluded++; } } RegressionParameters.KeywordsTestFilter kf = params.getKeywordsFilter(); if (kf != null) { ignored = kf.ignored.size(); } } @Override public void finishedTest(TestResult tr) { add(tr); } RegressionParameters params; }); } public void add(TestResult tr) { counts[tr.getStatus().getType()]++; } public void addAll(TestStats other) { for (int i = 0; i < counts.length; i++) counts[i] += other.counts[i]; } public boolean isOK() { return (counts[Status.FAILED] == 0 && counts[Status.ERROR] ==0); } public void showResultStats(PrintWriter out) { int p = counts[Status.PASSED]; int f = counts[Status.FAILED]; int e = counts[Status.ERROR]; int nr = counts[Status.NOT_RUN]; String msg; if (p + f + e + nr == 0) msg = i18n.getString("stats.noTests"); else { String format = System.getProperty("jtreg.stats.format"); if (format != null) msg = getText(format); else { msg = i18n.getString("stats.tests", p, ((p > 0) && (f + e + nr > 0) ? 1 : 0), f, ((f > 0) && ( e + nr > 0) ? 1 : 0), e, ((e > 0) && ( nr > 0) ? 1 : 0), nr); } } out.println(msg); } public void report(Report report) throws IOException { File reportDir = report.getReportDir(); File reportTextDir = new File(reportDir, "text"); reportTextDir.mkdirs(); File file = new File(reportTextDir, "stats.txt"); report(file); } public void report(File file) throws IOException { try (PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(file)))) { showResultStats(out); } } /* * Evaluate a format string. The following characters are supported. *

     * %f       number of failed tests
     * %F       number of failed and error tests
     * %e       number of error tests
     * %p       number of passed tests
     * %n       number of tests not run
     * %r       number of tests run
     * %x       number of excluded tests
     * %i       number of ignored tests
     * %,       conditional comma
     * % conditional space
     * %%       %
     * %?X      prints given number if not zero, where X is one of f, F, e, p, x, i
     * %?{textX} prints text and given number if number is not zero, where
     *              X is one of f, F, e, p, x, i
     * 
*/ String getText(String format) { StringBuilder sb = new StringBuilder(); int sbLen = 0; for (int i = 0; i < format.length(); i++) { char c = format.charAt(i); if (c == '%' && i + 1 < format.length()) { c = format.charAt(++i); switch (c) { case 'f': case 'F': case 'e': case 'i': case 'n': case 'p': case 'r': case 'x': { int count = getNumber(c); if (count >= 0) sb.append(String.valueOf(count)); else sb.append("%").append(c); break; } case ',': if (sb.length() > 0) sb.append(","); continue; // don't update sbLen case ' ': if (sb.length() > 0 && !Character.isWhitespace(sb.charAt(sb.length() - 1))) { sb.append(' '); } continue; // don't update sbLen case '%': sb.append("%"); break; case '?': if (i + 1 < format.length()) { c = format.charAt(++i); if (c == '{') { int j = format.indexOf("}", i); if (j == -1) { sb.append("%?").append(format.substring(i)); i = format.length(); } else { String text = format.substring(i + 1, j); i = j; if (text.length() > 0) { c = text.charAt(text.length() - 1); int count = getNumber(c); if (count > 0) { sb.append(text, 0, text.length() - 1) .append(String.valueOf(count)); } else if (count < 0) sb.append("%?{").append(text).append("}"); else { continue; // don't update sbLen } } } } else { int count = getNumber(c); if (count > 0) { sb.append(String.valueOf(count)); } else if (count < 0) { sb.append("%?").append(c); } else { continue; // don't update sbLen } break; } } else sb.append("%").append("?"); break; default: sb.append("%").append(c); } } else sb.append(c); sbLen = sb.length(); } return sb.substring(0, sbLen); } int getNumber(char c) { switch (c) { case 'f': return counts[Status.FAILED]; case 'F': return counts[Status.FAILED] + counts[Status.ERROR]; case 'e': return counts[Status.ERROR]; case 'i': return ignored; case 'n': return counts[Status.NOT_RUN]; case 'p': return counts[Status.PASSED]; case 'r': return counts[Status.PASSED] + counts[Status.FAILED] + counts[Status.ERROR]; case 'x': return excluded; default: return -1; } } public int[] counts = new int[Status.NUM_STATES]; int excluded; int ignored; private static final I18NResourceBundle i18n = I18NResourceBundle.getBundleForClass(TestStats.class); } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/report/Verbose.java000066400000000000000000000120041461415321300277350ustar00rootroot00000000000000/* * 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 * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.report; import java.util.HashSet; import java.util.List; import java.util.Set; /** * Values for the -verbose option */ public class Verbose { public enum Mode { NONE, DEFAULT, SUMMARY, BRIEF, FULL } public static final Verbose DEFAULT = new Verbose(Mode.DEFAULT); public static final Verbose SUMMARY = new Verbose(Mode.SUMMARY); public static final Verbose ALL = new Verbose(Mode.FULL); public static final Verbose PASS = new Verbose(Mode.FULL, Mode.BRIEF, Mode.BRIEF); public static final Verbose FAIL = new Verbose(Mode.BRIEF, Mode.FULL, Mode.BRIEF); public static final Verbose ERROR = new Verbose(Mode.BRIEF, Mode.BRIEF, Mode.FULL); public static final Verbose TIME = new Verbose(Mode.SUMMARY, true, false); public static String[] values() { return new String[] { "default", "summary", "all", "pass", "fail", "error", "nopass", "time", "multirun" }; } public static Verbose decode(String s) { // FIXME, check all words are valid? Set opts = new HashSet<>(List.of(s.split(","))); boolean defaultOpt = opts.contains("default"); boolean summaryOpt = opts.contains("summary"); boolean allOpt = opts.contains("all"); boolean passOpt = opts.contains("pass"); boolean failOpt = opts.contains("fail"); boolean errorOpt = opts.contains("error"); boolean nopassOpt = opts.contains("nopass"); boolean timeOpt = opts.contains("time"); boolean multiRunOpt = opts.contains("multirun"); if (defaultOpt) { if (summaryOpt || allOpt || passOpt || failOpt || errorOpt || nopassOpt) throw new IllegalArgumentException(s); return new Verbose(Mode.DEFAULT, timeOpt, multiRunOpt); } if (summaryOpt || allOpt || passOpt || failOpt || errorOpt || nopassOpt) { if (passOpt && nopassOpt) throw new IllegalArgumentException(s); Mode shortMode = summaryOpt ? Mode.SUMMARY : Mode.BRIEF; return new Verbose( nopassOpt ? Mode.NONE : (allOpt || passOpt) ? Mode.FULL : shortMode, (allOpt || failOpt) ? Mode.FULL : shortMode, (allOpt || errorOpt) ? Mode.FULL : shortMode, timeOpt, multiRunOpt); } if (timeOpt) return new Verbose(Mode.SUMMARY, true, multiRunOpt); else return new Verbose(Mode.DEFAULT, false, multiRunOpt); } private static Mode check(Mode currentMode, Mode newMode) { if (newMode == null) throw new NullPointerException(); if (currentMode == null || currentMode == newMode) return newMode; return newMode; } Verbose(Mode m) { this(m, false, false); } Verbose(Mode m, boolean time, boolean multiRun) { this(m, m, m, time, multiRun); } Verbose(Mode p, Mode f, Mode e) { this(p, f, e, false, false); } Verbose(Mode p, Mode f, Mode e, boolean t, boolean m) { passMode = p; failMode = f; errorMode = e; time = t; multiRun = m; } boolean isDefault() { return (passMode == Mode.DEFAULT) && (failMode == Mode.DEFAULT) && (errorMode == Mode.DEFAULT); } @Override public String toString() { return "Verbose[p=" + passMode + ",f=" + failMode + ",e=" + errorMode + ",t=" + time + ",m=" + multiRun + "]"; } public final Mode passMode; public final Mode failMode; public final Mode errorMode; public final boolean time; public final boolean multiRun; } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/report/VerboseHandler.java000066400000000000000000000256041461415321300312450ustar00rootroot00000000000000/* * Copyright (c) 2006, 2018, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.report; import java.io.PrintWriter; import com.sun.javatest.Harness; import com.sun.javatest.Status; import com.sun.javatest.TestDescription; import com.sun.javatest.TestResult; // TODO: I18N public class VerboseHandler { public VerboseHandler(Verbose verbose, PrintWriter out, PrintWriter err) { this.verbose = verbose; this.out = out; this.err = err; } public void register(Harness h) { h.addObserver(new BasicObserver() { @Override public synchronized void startingTest(TestResult tr) { VerboseHandler.this.startingTest(tr); } @Override public synchronized void finishedTest(TestResult tr) { VerboseHandler.this.finishedTest(tr); } }); } private void startingTest(TestResult tr) { if (verbose.isDefault()) { try { TestDescription td = tr.getDescription(); out.println("runner starting test: " + td.getRootRelativeURL()); } catch(TestResult.Fault e) { e.printStackTrace(System.err); } } } // starting() private void finishedTest(TestResult tr) { Verbose.Mode m; switch (tr.getStatus().getType()) { case Status.PASSED: m = verbose.passMode; break; case Status.FAILED: m = verbose.failMode; break; case Status.ERROR: m = verbose.errorMode; break; default: m = Verbose.Mode.NONE; } switch (m) { case NONE: break; case DEFAULT: try { TestDescription td = tr.getDescription(); if (verbose.time) printElapsedTimes(tr); out.println("runner finished test: " + td.getRootRelativeURL()); out.println(tr.getStatus()); } catch (TestResult.Fault e) { e.printStackTrace(System.err); } break; case SUMMARY: printSummary(tr, verbose.time); break; case BRIEF: printBriefOutput(tr, verbose.time); break; case FULL: printFullOutput(tr); break; } } // finished() /** * Print out one line per test indicating the status category for the * named test. * * @param tr TestResult containing all recorded information from a * test's run. */ private void printSummary(TestResult tr, boolean times) { try { TestDescription td = tr.getDescription(); String msg; if (tr.getStatus().isPassed()) msg = "Passed: "; else if (tr.getStatus().isFailed()) msg = "FAILED: "; else if (tr.getStatus().isError()) msg = "Error: "; else msg = "Unexpected status: "; msg += td.getRootRelativeURL(); out.println(msg); if (times) printElapsedTimes(tr); } catch (TestResult.Fault e) { e.printStackTrace(System.err); } } // printSummary() /** * Print out two lines per test indicating the name of the test and the * final status. * * @param tr TestResult containing all recorded information from a * test's run. */ private void printBriefOutput(TestResult tr, boolean times) { if (!doneSeparator) { out.println(VERBOSE_TEST_SEP); doneSeparator = true; } try { TestDescription td = tr.getDescription(); out.println("TEST: " + td.getRootRelativeURL()); if (times) printElapsedTimes(tr); out.println("TEST RESULT: " + tr.getStatus()); } catch (TestResult.Fault e) { e.printStackTrace(System.err); } out.println(VERBOSE_TEST_SEP); } // printBriefOutput() /** * Print out full information for the test. This includes the reason * for running each action, the action's output streams, the final * status, etc. This is meant to encompass all of the information * from the .jtr file that the average user would find useful. * * @param tr TestResult containing all recorded information from a * test's run. */ private void printFullOutput(TestResult tr) { if (!doneSeparator) { out.println(VERBOSE_TEST_SEP); doneSeparator = true; } try { TestDescription td = tr.getDescription(); out.println("TEST: " + td.getRootRelativeURL()); String testJDK = getTestJDK(tr); if (testJDK != null) { out.println("TEST JDK: " + testJDK); } StringBuilder sb = new StringBuilder(); for (int i = 1; i < tr.getSectionCount(); i++) { TestResult.Section section = tr.getSection(i); sb.append(LINESEP); sb.append("ACTION: ").append(section.getTitle()); sb.append(" -- ").append(section.getStatus()).append(LINESEP); sb.append("REASON: ").append(getReason(section)).append(LINESEP); sb.append("TIME: ").append(getElapsedTime(section)); sb.append(" seconds").append(LINESEP); String[] outputNames = section.getOutputNames(); for (String name : outputNames) { String output = section.getOutput(name); switch (name) { case "System.out": sb.append("STDOUT:").append(LINESEP).append(output); break; case "System.err": sb.append("STDERR:").append(LINESEP).append(output); break; default: sb.append(name).append(":").append(LINESEP).append(output); break; } } } out.println(sb.toString()); out.println("TEST RESULT: " + tr.getStatus()); out.println(VERBOSE_TEST_SEP); } catch (TestResult.Fault e) { e.printStackTrace(System.err); } } // printFullOutput() /** * Print out one line per test indicating the status category for the * named test and the elapsed time per action in the test. * * @param tr TestResult containing all recorded information from a * test's run. */ private void printElapsedTimes(TestResult tr) { StringBuilder sb = new StringBuilder(); try { for (int i = 1; i < tr.getSectionCount(); i++) { TestResult.Section section = tr.getSection(i); sb.append(" ").append(section.getTitle()).append(": "); sb.append(getElapsedTime(section)).append(" seconds").append(LINESEP); } out.print(sb.toString()); } catch (TestResult.ReloadFault f) { f.printStackTrace(System.err); } } // printElapsedTimes() /** * Find the reason that the action was run. This method takes * advantage of the fact that the reason string begins with * {@code reason: }, ends with a line separator. * * @param section The recorded information for a single action. * @return The reason string without the beginning * {@code reason: } * string. */ private String getReason(TestResult.Section section) { String msg = section.getOutput(TestResult.MESSAGE_OUTPUT_NAME); int posStart = msg.indexOf("reason: ") + "reason: ".length(); int posEnd = msg.indexOf(LINESEP, posStart); return msg.substring(posStart, posEnd); } // getReason() /** * Find the elapsed time for the action. This method takes advantage * of the fact that the string containing the elapsed time begins with * {@code elapsed time (seconds): }, and ends with a line * separator. * * @param section The recorded information for a single action. * @return The elapsed time without the beginning {@code elapsed time * (seconds): } as a string. */ private String getElapsedTime(TestResult.Section section) { String msg = section.getOutput(TestResult.MESSAGE_OUTPUT_NAME); int posStart = msg.indexOf("elapsed time (seconds): ") + "elapsed time (seconds): ".length(); int posEnd = msg.indexOf(LINESEP, posStart); return msg.substring(posStart, posEnd); } // getElapsedTime() /** * Find the JDK under test. * * @param tr The test result where all sections are stored. * @return The string indicating the JDK under test, or null if not found */ private String getTestJDK(TestResult tr) { try { return tr.getProperty("testJDK"); } catch (TestResult.Fault f) { f.printStackTrace(System.err); } return null; } // getTestJDK() //----------member variables------------------------------------------- private static final String VERBOSE_TEST_SEP = "--------------------------------------------------"; private static final String LINESEP = System.getProperty("line.separator"); private final Verbose verbose; private final PrintWriter out; private final PrintWriter err; private boolean doneSeparator; } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/report/XMLWriter.java000066400000000000000000000401551461415321300301750ustar00rootroot00000000000000/* * Copyright (c) 2011, 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.report; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.ArrayList; import java.util.Date; import java.util.Enumeration; import java.util.Iterator; import java.util.List; import java.util.Locale; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import com.sun.javatest.Status; import com.sun.javatest.TestDescription; import com.sun.javatest.TestResult; import com.sun.javatest.TestResult.Section; /** * Write out results in JUnit-compatible XML format, for processing by tools * that can process such files, such as CI systems like Hudson and Jenkins. */ public class XMLWriter { static final String PASSED = "Passed."; static final String FAILED = "Failed."; public final TestResult tr; private final XPrintStream xps; private final String classname; private final Date start; private final double duration; private final Status status; private final File xmlFile; private final boolean verify; private final PrintWriter harnessOut; private final PrintWriter harnessErr; private final SimpleDateFormat defDateFmt; private final DateFormat isoDateFmt; XMLWriter(TestResult tr, boolean mustVerify, PrintWriter out, PrintWriter err) throws ParseException, UnsupportedEncodingException, TestResult.Fault { String encoding = Charset.defaultCharset().name(); defDateFmt = new SimpleDateFormat("EEE MMM dd hh:mm:ss z yyyy", Locale.US); isoDateFmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); harnessOut = out; harnessErr = err; xps = new XPrintStream(harnessOut, harnessErr, encoding); this.tr = tr; verify = mustVerify; status = tr.getStatus(); classname = tr.getProperty("test"); xmlFile = new File(tr.getFile().getAbsolutePath() + ".xml"); start = defDateFmt.parse(tr.getProperty("start")); duration = getElapsedTime(); process(encoding); } private double getElapsedTime() throws TestResult.Fault { String elapsedTime = tr.getProperty("elapsed"); if (elapsedTime == null) { elapsedTime = tr.getProperty("totalTime"); } if (elapsedTime == null) { return 0.0; } String[] f = elapsedTime.split("\\s"); double elapsed = Double.parseDouble(f[0]); return elapsed/1000; } private void createHeader(String encoding) { xps.println(""); } private void startTestSuite() throws TestResult.Fault { xps.print(""); } private void endTestSuite() { xps.println(""); } private void insertProperties() throws TestResult.Fault { xps.indent(); xps.println(""); TestDescription td = tr.getDescription(); Iterator iterator = td.getParameterKeys(); while (iterator.hasNext()) { String key = iterator.next(); xps.indent(2); xps.print(""); } Enumeration e = tr.getPropertyNames(); while (e.hasMoreElements()) { String x = e.nextElement(); xps.indent(2); xps.print(""); } xps.indent(); xps.println(""); } private String getOutput(String name) throws TestResult.Fault { String[] titles = tr.getSectionTitles(); //we are looking for either a "main" section or "shell" section in jtr log for (int i = 0; i < titles.length; i++) { if (titles[i].equals("main") || titles[i].equals("shell")) { Section s = tr.getSection(i); for (String x : s.getOutputNames()) { return s.getOutput(name); } } } return ""; } private void insertSystemOut() throws TestResult.Fault { xps.indent(); xps.print(""); xps.sanitize(getOutput("System.out")); xps.indent(); xps.println(""); } private void insertSystemErr() throws TestResult.Fault { xps.indent(); xps.print(""); xps.sanitize(getOutput("System.err")); xps.indent(); xps.println(""); } private void insertFailure() { if (status.isPassed()) return; xps.indent(); xps.print(""); xps.sanitize(status.getReason()); xps.indent(); xps.println(""); xps.println(""); } private void insertTestCase() throws TestResult.Fault { xps.indent(); xps.print(""); insertFailure(); xps.indent(); xps.println(""); } private void process(String encoding) throws TestResult.Fault { createHeader(encoding); startTestSuite(); insertProperties(); insertTestCase(); insertSystemOut(); insertSystemErr(); endTestSuite(); } @Override public String toString() { return xps.toString(); } public void toXML() throws IOException { File baseDir = xmlFile.getParentFile(); if (!baseDir.exists()) { baseDir.mkdirs(); } try (FileOutputStream fos = new FileOutputStream(xmlFile)) { xps.writeTo(fos); } if (verify) xps.verifyXML(xmlFile); } private static void usage(PrintStream out, String message) { if (message != null) { out.println(message); } out.println("Usage:"); out.println(" java -cp jtreg.jar com.sun.javatest.regtest.XMLWriter -@list"); out.println(" where list is a file containing the .jtr files to be processed"); out.println(" java -cp jtreg.jar com.sun.javatest.regtest.XMLWriter dir"); out.println(" where dir is a JTwork dir containing the .jtr files to be processed"); out.println(" java -cp jtreg.jar com.sun.javatest.regtest.XMLWriter 1.jtr 2.jtr.. n.jtr"); out.println(" where args are a list of .jtr files to be processed"); System.exit(1); } private static List fileToList(String arg) throws Exception { List outList = new ArrayList<>(); String in = arg.replaceFirst("^-@|^@", ""); try (BufferedReader br = new BufferedReader(new FileReader(in))) { String line = br.readLine(); while (line != null) { outList.add(new File(line)); line = br.readLine(); } } return outList; } private static void scan(File file, List xlist) { if (file.isFile() && file.getName().endsWith(".jtr")) { xlist.add(file); } else if (file.isDirectory()) { for (File f : file.listFiles()) { scan(f, xlist); } } } private static List dirToList(File f) { List outList = new ArrayList<>(); scan(f, outList); return outList; } private static void translateList(List xmlFileList) throws Exception { if (xmlFileList == null || xmlFileList.isEmpty()) { usage(System.out, "Warning: nothing to process"); return; } for (File jtrFile : xmlFileList) { if (jtrFile.exists() && jtrFile.isFile() && jtrFile.getName().endsWith(".jtr")) { XMLWriter jutr = new XMLWriter(new TestResult(jtrFile), true, new PrintWriter(System.out, true), new PrintWriter(System.err, true)); jutr.toXML(); } else { System.out.println("Warning: skipping file " + jtrFile); } } } private static List argsToList(String... args) { List outList = new ArrayList<>(); for (String x : args) { outList.add(new File(x)); } return outList; } // utility to populate a previous run with xml files public static void main(String[] args) { try { if (args == null || args.length < 1 ) { usage(System.err, "Error: insufficent arguments"); } if (args[0].startsWith("-@") || args[0].startsWith("@")) { translateList(fileToList(args[0])); } else { File f = new File(args[0]); if (f.isDirectory()) { translateList(dirToList(f)); } else { translateList(argsToList(args)); } } } catch (Exception ex) { ex.printStackTrace(System.err); System.exit(1); } } public static class XMLHarnessObserver extends BasicObserver { private final boolean mustVerify; private final PrintWriter harnessOut; private final PrintWriter harnessErr; public XMLHarnessObserver(boolean mustVerify, PrintWriter out, PrintWriter err) { harnessOut = out; harnessErr = err; this.mustVerify = mustVerify; } @Override public void finishedTest(TestResult tr) { try { super.finishedTest(tr); new XMLWriter(tr, mustVerify, harnessOut, harnessErr).toXML(); } catch (IOException | ParseException | TestResult.Fault ex) { ex.printStackTrace(harnessOut); } } } } class XPrintStream { private final ByteArrayOutputStream bstream; private final PrintStream ps; private final PrintWriter out; private final PrintWriter err; private static final String INDENT = " "; XPrintStream(PrintWriter out, PrintWriter err, String encoding) throws UnsupportedEncodingException { this.out = out; this.err = err; this.bstream = new ByteArrayOutputStream(); this.ps = new PrintStream(bstream, false, encoding); } void indent() { ps.print(INDENT); } public void indent(int n) { for (int i = 0; i < n; i++) { indent(); } } public void println(String in) { ps.println(in); } public void print(String in) { ps.print(in); } public void print(double d) { ps.print(d); } // sanitize the string for xml presentation public void sanitize(String in) { if (in == null) return; for (int i = 0; i < in.length(); i++) { char ch = in.charAt(i); switch (ch) { case '&': ps.print("&"); break; case '<': ps.print("<"); break; case '>': ps.print(">"); break; case '"': ps.print("""); break; case '\'': ps.print("'"); break; // case 'f': // not a valid XML character case '\n': case '\r': case '\t': ps.print(ch); break; case '\\': if (i + 1 < in.length() && in.charAt(i + 1) == 'u') { // encode "backslash u" as "backslash u u" to distinguish // it from use of unicode escapes for control characters. ps.print("\\uu"); i++; } else { ps.print(ch); } break; default: if (ch < 32 || !Character.isDefined(ch)) { // Ideally, we'd print control characters as numeric // character entities, but a validating SAX parser // rejects that, so we encode them as Unicode instead. ps.printf("\\u%04x", (int) ch); } else { ps.print(ch); } } } } public void close() { ps.close(); } @Override public String toString() { return bstream.toString(); } public void writeTo(OutputStream os) throws IOException { bstream.writeTo(os); } // we don't want to see errors in hudson and it may take a while, depending // on the job, so we verify for xml conformance. public void verifyXML(File xmlFile) throws IOException { try { SAXParserFactory sax = SAXParserFactory.newInstance(); sax.setValidating(false); SAXParser parser = sax.newSAXParser(); XMLReader xmlreader = parser.getXMLReader(); xmlreader.parse(new InputSource(new ByteArrayInputStream(bstream.toByteArray()))); //out.println("File: " + xmlFile + ": verified"); } catch (IOException | ParserConfigurationException | SAXException ex) { err.println("File: " + xmlFile + ":" + ex); err.println(toString()); } } } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/report/i18n.properties000066400000000000000000000027051461415321300303710ustar00rootroot00000000000000# # Copyright (c) 1999, 2016, 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. Oracle designates this # particular file as subject to the "Classpath" exception as provided # by Oracle in the LICENSE file that accompanied this code. # # 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. # stats.noTests=Test results: no tests selected stats.tests=Test results: \ {0,choice,0#|0This is NOT part of any supported API. * If you write code that depends on this, you do so at your own risk. * This code and its internal interfaces are subject to change or * deletion without notice. */ package com.sun.javatest.regtest.report; jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/tool/000077500000000000000000000000001461415321300251325ustar00rootroot00000000000000jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/tool/ExcludeFileVerifier.java000066400000000000000000000120761461415321300316700ustar00rootroot00000000000000/* * 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. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.tool; import java.io.BufferedReader; import java.io.FileReader; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintWriter; import java.nio.file.Path; import java.util.ArrayList; import java.util.function.Predicate; import java.util.List; import java.util.regex.Pattern; public class ExcludeFileVerifier { private PrintWriter out; public ExcludeFileVerifier(PrintWriter out) { this.out = out; } private boolean hadErrors = false; public boolean getHadErrors() { return hadErrors; } public boolean verify(File file, List validTestNames) { var usedTestNames = new ArrayList(); var checks = new ArrayList(); checks.add(new LineFormatCheck()); checks.add(new TestExistsCheck(validTestNames)); checks.add(new DuplicateCheck(usedTestNames)); try { BufferedReader br = new BufferedReader(new FileReader(file)); String line = null; int n = 0; while ((line = br.readLine()) != null) { n++; if (lineIsComment(line.trim())) continue; for (Check c : checks) { if(!c.check(line.trim())) { out.println(file.getAbsolutePath() + " line " + n + " is invalid. Reason:"); out.println(c.description()); out.println("Line contents:"); out.println("--------------"); out.println(line); out.println("--------------"); hadErrors = true; break; } } usedTestNames.add(testName(line)); } } catch (FileNotFoundException e) { System.out.println("File does not exist: " + file.getAbsolutePath()); } catch (IOException e) { System.out.println("File cannot be read: " + file.getAbsolutePath()); } return true; } static boolean lineIsComment(String line) { return line.isBlank() || line.trim().startsWith("#"); } private static String testName(String line) { line = line.trim(); String[] words = line.split("\\s+"); return words.length >= 1 ? words[0] : null; } abstract static class Check { public abstract String description(); public abstract boolean check(String line); } static class LineFormatCheck extends Check { private static final String commalist = "([\\w-]+)(,[\\w-]+)*"; private static Pattern pattern = Pattern.compile("\\S+\\s+" + commalist + "\\s" + commalist + ".*"); public String description() { return "Must follow: (,)* (,)* "; } public boolean check(String line) { return pattern.matcher(line).matches(); } } static class TestExistsCheck extends Check { private List validTestNames; public TestExistsCheck(List validTestNames) { this.validTestNames = validTestNames; } public String description() { return "The fully qualified test must exists."; } public boolean check(String line) { return validTestNames.contains(testName(line)); } } static class DuplicateCheck extends Check { private List usedTestNames; public DuplicateCheck(List usedTestNames) { this.usedTestNames = usedTestNames; } public String description() { return "Exclude file cannot contain duplicate entries."; } public boolean check(String line) { return !usedTestNames.contains(testName(line)); } } } jtreg-jtreg-7.4-1/src/share/classes/com/sun/javatest/regtest/tool/Help.java000066400000000000000000000440121461415321300266660ustar00rootroot00000000000000/* * 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 * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * 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 com.sun.javatest.regtest.tool; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; import java.io.PrintWriter; import java.lang.reflect.Field; import java.net.MalformedURLException; import java.net.URL; import java.nio.file.Path; import java.text.DateFormat; import java.util.ArrayList; import java.util.Comparator; import java.util.Enumeration; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import java.util.jar.Attributes; import java.util.jar.JarFile; import java.util.stream.Collectors; import com.sun.javatest.regtest.agent.SearchPath; import com.sun.javatest.util.HelpTree; import com.sun.javatest.util.I18NResourceBundle; import com.sun.javatest.util.WrapWriter; /** * Handles help options for main program */ public class Help { interface VersionHelper { void showVersion(PrintWriter out); } /** * Creates a new instance of Help * @param options the options to be documented in the help output */ public Help(List