From 919350144829e964b0a7309f377d165982f8c1fa Mon Sep 17 00:00:00 2001 From: himanshu748 Date: Sun, 22 Feb 2026 16:09:13 +0530 Subject: [PATCH 1/3] [JENKINS-27993] Increase @Exported visibility on PluginWrapper properties The /pluginManager/api/json endpoint returned empty objects for each plugin because all @Exported properties had default visibility (1), which is not rendered when nested inside PluginManager at the default API depth. Increase visibility to 2 on key properties (shortName, version, longName, displayName, url, active, enabled, hasUpdate) so they appear at the default depth. Also add @Exported to getDisplayName() as the non-deprecated replacement for getLongName(). --- core/src/main/java/hudson/PluginWrapper.java | 15 ++++----- .../test/java/hudson/PluginManagerTest.java | 31 +++++++++++++++++++ 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/hudson/PluginWrapper.java b/core/src/main/java/hudson/PluginWrapper.java index a77df0d3bca6..a15117ef95c2 100644 --- a/core/src/main/java/hudson/PluginWrapper.java +++ b/core/src/main/java/hudson/PluginWrapper.java @@ -522,6 +522,7 @@ public PluginWrapper(PluginManager parent, File archive, Manifest manifest, URL this.archive = archive; } + @Exported(visibility = 2) @Override public String getDisplayName() { String displayName = getLongName(); @@ -595,7 +596,7 @@ public List getOptionalDependencies() { /** * Returns the short name suitable for URL. */ - @Exported + @Exported(visibility = 2) public String getShortName() { return shortName; } @@ -627,7 +628,7 @@ public String getShortName() { * null if this information is unavailable. * @since 1.283 */ - @Exported + @Exported(visibility = 2) public String getUrl() { // first look in update center metadata List siteMetadataList = getInfoFromAllSites(); @@ -662,7 +663,7 @@ public String toString() { * * @deprecated For most purposes, use {@link #getDisplayName()}. */ - @Exported + @Exported(visibility = 2) @Deprecated public String getLongName() { String name = manifest.getMainAttributes().getValue("Long-Name"); @@ -683,7 +684,7 @@ public YesNoMaybe supportsDynamicLoad() { /** * Returns the version number of this plugin */ - @Exported + @Exported(visibility = 2) public String getVersion() { return getVersionOf(manifest); } @@ -894,7 +895,7 @@ private Set dependentsToCheck(PluginDisableStrategy strategy) { /** * Returns true if this plugin is enabled for this session. */ - @Exported + @Exported(visibility = 2) public boolean isActive() { return active && !hasCycleDependency(); } @@ -921,7 +922,7 @@ public boolean isBundled() { * If true, the plugin is going to be activated next time * Jenkins runs. */ - @Exported + @Exported(visibility = 2) public boolean isEnabled() { return !disableFile.exists(); } @@ -1080,7 +1081,7 @@ private List getInfoFromAllSites() { * This method is conservative in the sense that if the version number is incomprehensible, * it always returns false. */ - @Exported + @Exported(visibility = 2) public boolean hasUpdate() { return getUpdateInfo() != null; } diff --git a/test/src/test/java/hudson/PluginManagerTest.java b/test/src/test/java/hudson/PluginManagerTest.java index 8c8306b94d87..367491431768 100644 --- a/test/src/test/java/hudson/PluginManagerTest.java +++ b/test/src/test/java/hudson/PluginManagerTest.java @@ -542,6 +542,37 @@ void pluginListJSONApi() throws Throwable { }); } + @Issue("JENKINS-27993") + @WithPlugin("htmlpublisher.jpi") + @Test + void pluginManagerApiJsonReturnsPluginDetails() throws Throwable { + session.then(r -> { + JSONObject response = r.getJSON("pluginManager/api/json").getJSONObject(); + JSONArray plugins = response.getJSONArray("plugins"); + assertThat(plugins, not(empty())); + + // Find the htmlpublisher plugin in the response + JSONObject htmlPublisher = null; + for (int i = 0; i < plugins.size(); i++) { + JSONObject plugin = plugins.getJSONObject(i); + if ("htmlpublisher".equals(plugin.optString("shortName"))) { + htmlPublisher = plugin; + break; + } + } + assertNotNull(htmlPublisher, "htmlpublisher plugin should be present in API response"); + + // Verify key properties are present at default depth (visibility = 2) + assertNotNull(htmlPublisher.optString("shortName", null), "shortName should be exported at default depth"); + assertNotNull(htmlPublisher.optString("version", null), "version should be exported at default depth"); + assertNotNull(htmlPublisher.optString("longName", null), "longName should be exported at default depth"); + assertNotNull(htmlPublisher.optString("displayName", null), "displayName should be exported at default depth"); + assertTrue(htmlPublisher.has("active"), "active should be exported at default depth"); + assertTrue(htmlPublisher.has("enabled"), "enabled should be exported at default depth"); + assertTrue(htmlPublisher.has("hasUpdate"), "hasUpdate should be exported at default depth"); + }); + } + @Issue("JENKINS-41684") @Test void requireSystemDuringLoad() throws Throwable { From ee34d759734339219f91b8971177d0df9c4dadb0 Mon Sep 17 00:00:00 2001 From: himanshu748 Date: Tue, 24 Feb 2026 10:50:10 +0530 Subject: [PATCH 2/3] Address PR feedback - Remove @Exported from deprecated properties lengthName & backupVersion - Fix Issue link in PluginManagerTest from JENKINS-27993 to issues/21047 --- core/src/main/java/hudson/PluginWrapper.java | 2 +- .../test/java/hudson/PluginManagerTest.java | 239 ++++++++++-------- 2 files changed, 137 insertions(+), 104 deletions(-) diff --git a/core/src/main/java/hudson/PluginWrapper.java b/core/src/main/java/hudson/PluginWrapper.java index a15117ef95c2..094b79ce9bfa 100644 --- a/core/src/main/java/hudson/PluginWrapper.java +++ b/core/src/main/java/hudson/PluginWrapper.java @@ -663,7 +663,7 @@ public String toString() { * * @deprecated For most purposes, use {@link #getDisplayName()}. */ - @Exported(visibility = 2) + @Exported @Deprecated public String getLongName() { String name = manifest.getMainAttributes().getValue("Long-Name"); diff --git a/test/src/test/java/hudson/PluginManagerTest.java b/test/src/test/java/hudson/PluginManagerTest.java index 367491431768..fa4b300b3d65 100644 --- a/test/src/test/java/hudson/PluginManagerTest.java +++ b/test/src/test/java/hudson/PluginManagerTest.java @@ -174,7 +174,8 @@ void deployJpiFromUrl() throws Throwable { session.then(r -> { HtmlPage page = r.createWebClient().goTo("pluginManager/advanced"); HtmlForm f = page.getFormByName("uploadPlugin"); - f.getInputByName("pluginUrl").setValue(Jenkins.get().getRootUrl() + "pluginManagerGetPlugin/htmlpublisher.jpi"); + f.getInputByName("pluginUrl") + .setValue(Jenkins.get().getRootUrl() + "pluginManagerGetPlugin/htmlpublisher.jpi"); r.submit(f); assertTrue(new File(r.jenkins.getRootDir(), "plugins/htmlpublisher.jpi").exists()); @@ -199,10 +200,12 @@ public String getUrlName() { return "pluginManagerGetPlugin"; } - public void doDynamic(StaplerRequest2 staplerRequest, StaplerResponse2 staplerResponse) throws ServletException, IOException { + public void doDynamic(StaplerRequest2 staplerRequest, StaplerResponse2 staplerResponse) + throws ServletException, IOException { staplerResponse.setContentType("application/octet-stream"); staplerResponse.setStatus(200); - staplerResponse.serveFile(staplerRequest, PluginManagerTest.class.getClassLoader().getResource("plugins/htmlpublisher.jpi")); + staplerResponse.serveFile(staplerRequest, + PluginManagerTest.class.getClassLoader().getResource("plugins/htmlpublisher.jpi")); } } @@ -225,16 +228,21 @@ void withRecipeHpi() throws Throwable { } /** - * Verifies that by the time {@link Plugin#start()} is called, uber classloader is fully functioning. - * This is necessary as plugin start method can engage in XStream loading activities, and they should - * resolve all the classes in the system (for example, a plugin X can define an extension point - * other plugins implement, so when X loads its config it better sees all the implementations defined elsewhere) + * Verifies that by the time {@link Plugin#start()} is called, uber classloader + * is fully functioning. + * This is necessary as plugin start method can engage in XStream loading + * activities, and they should + * resolve all the classes in the system (for example, a plugin X can define an + * extension point + * other plugins implement, so when X loads its config it better sees all the + * implementations defined elsewhere) */ @WithPlugin("htmlpublisher.jpi") @WithPluginManager(PluginManagerImpl_for_testUberClassLoaderIsAvailableDuringStart.class) @Test void uberClassLoaderIsAvailableDuringStart() throws Throwable { - session.then(r -> assertTrue(((PluginManagerImpl_for_testUberClassLoaderIsAvailableDuringStart) r.jenkins.pluginManager).tested)); + session.then(r -> assertTrue( + ((PluginManagerImpl_for_testUberClassLoaderIsAvailableDuringStart) r.jenkins.pluginManager).tested)); } public static class PluginManagerImpl_for_testUberClassLoaderIsAvailableDuringStart extends LocalPluginManager { @@ -263,9 +271,9 @@ public void startPlugin(PluginWrapper plugin) throws Exception { } } - /** - * Makes sure that thread context classloader isn't used by {@link UberClassLoader}, or else + * Makes sure that thread context classloader isn't used by + * {@link UberClassLoader}, or else * infinite cycle ensues. */ @Url("http://jenkins.361315.n4.nabble.com/channel-example-and-plugin-classes-gives-ClassNotFoundException-td3756092.html") @@ -296,7 +304,8 @@ void installWithoutRestart() throws Throwable { FileUtils.copyURLToFile(res, f); r.jenkins.pluginManager.dynamicLoad(f); - Class c = r.jenkins.getPluginManager().uberClassLoader.loadClass("htmlpublisher.HtmlPublisher$DescriptorImpl"); + Class c = r.jenkins.getPluginManager().uberClassLoader + .loadClass("htmlpublisher.HtmlPublisher$DescriptorImpl"); assertNotNull(r.jenkins.getDescriptorByType(c)); }); } @@ -312,16 +321,21 @@ void prevalidateConfig() throws Throwable { sites.add(site); assertEquals(FormValidation.ok(), site.updateDirectly(false).get()); assertNotNull(site.getData()); - assertEquals(Collections.emptyList(), r.jenkins.getPluginManager().prevalidateConfig(new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8)))); + assertEquals(Collections.emptyList(), + r.jenkins.getPluginManager().prevalidateConfig(new ByteArrayInputStream( + "".getBytes(StandardCharsets.UTF_8)))); assertNull(r.jenkins.getPluginManager().getPlugin("htmlpublisher")); - List> jobs = r.jenkins.getPluginManager().prevalidateConfig(new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8))); + List> jobs = r.jenkins.getPluginManager().prevalidateConfig( + new ByteArrayInputStream("" + .getBytes(StandardCharsets.UTF_8))); assertEquals(1, jobs.size()); UpdateCenterJob job = jobs.getFirst().get(); // blocks for completion assertEquals("InstallationJob", job.getType()); UpdateCenter.InstallationJob ijob = (UpdateCenter.InstallationJob) job; assertEquals("htmlpublisher", ijob.plugin.name); assertNotNull(r.jenkins.getPluginManager().getPlugin("htmlpublisher")); - // TODO restart scheduled (SuccessButRequiresRestart) after upgrade or Support-Dynamic-Loading: false + // TODO restart scheduled (SuccessButRequiresRestart) after upgrade or + // Support-Dynamic-Loading: false // TODO dependencies installed or upgraded too // TODO required plugin installed but inactive }); @@ -330,35 +344,35 @@ void prevalidateConfig() throws Throwable { // plugin "depender" optionally depends on plugin "dependee". // they are written like this: // org.jenkinsci.plugins.dependencytest.dependee: - // public class Dependee { - // public static String getValue() { - // return "dependee"; - // } - // } + // public class Dependee { + // public static String getValue() { + // return "dependee"; + // } + // } // - // public abstract class DependeeExtensionPoint implements ExtensionPoint { - // } + // public abstract class DependeeExtensionPoint implements ExtensionPoint { + // } // // org.jenkinsci.plugins.dependencytest.depender: - // public class Depender { - // public static String getValue() { - // if (Jenkins.get().getPlugin("dependee") != null) { - // return Dependee.getValue(); - // } - // return "depender"; - // } - // } + // public class Depender { + // public static String getValue() { + // if (Jenkins.get().getPlugin("dependee") != null) { + // return Dependee.getValue(); + // } + // return "depender"; + // } + // } // - // @Extension(optional=true) - // public class DependerExtension extends DependeeExtensionPoint { - // } - + // @Extension(optional=true) + // public class DependerExtension extends DependeeExtensionPoint { + // } /** * call org.jenkinsci.plugins.dependencytest.depender.Depender.getValue(). */ private String callDependerValue(JenkinsRule r) throws Exception { - Class c = r.jenkins.getPluginManager().uberClassLoader.loadClass("org.jenkinsci.plugins.dependencytest.depender.Depender"); + Class c = r.jenkins.getPluginManager().uberClassLoader + .loadClass("org.jenkinsci.plugins.dependencytest.depender.Depender"); Method m = c.getMethod("getValue"); return (String) m.invoke(null); } @@ -379,7 +393,9 @@ void installDependingPluginWithoutRestart() throws Throwable { assertThrows(ClassNotFoundException.class, () -> callDependerValue(r)); // No extensions exist. - assertTrue(r.jenkins.getExtensionList("org.jenkinsci.plugins.dependencytest.dependee.DependeeExtensionPoint").isEmpty()); + assertTrue( + r.jenkins.getExtensionList("org.jenkinsci.plugins.dependencytest.dependee.DependeeExtensionPoint") + .isEmpty()); // Load depender. { @@ -390,7 +406,9 @@ void installDependingPluginWithoutRestart() throws Throwable { assertEquals("dependee", callDependerValue(r)); // Extension in depender is loaded. - assertFalse(r.jenkins.getExtensionList("org.jenkinsci.plugins.dependencytest.dependee.DependeeExtensionPoint").isEmpty()); + assertFalse( + r.jenkins.getExtensionList("org.jenkinsci.plugins.dependencytest.dependee.DependeeExtensionPoint") + .isEmpty()); }); } @@ -411,9 +429,11 @@ void installDependedPluginWithoutRestart() throws Throwable { assertEquals("depender", callDependerValue(r)); // before load dependee, of course failed to list extensions for dependee. - assertThrows(ClassNotFoundException.class, () -> r.jenkins.getExtensionList("org.jenkinsci.plugins.dependencytest.dependee.DependeeExtensionPoint")); + assertThrows(ClassNotFoundException.class, () -> r.jenkins + .getExtensionList("org.jenkinsci.plugins.dependencytest.dependee.DependeeExtensionPoint")); // Extension extending a dependee class can't be loaded either - assertThrows(NoClassDefFoundError.class, () -> r.jenkins.getExtensionList("org.jenkinsci.plugins.dependencytest.depender.DependerExtension")); + assertThrows(NoClassDefFoundError.class, () -> r.jenkins + .getExtensionList("org.jenkinsci.plugins.dependencytest.depender.DependerExtension")); // Load dependee. { @@ -425,7 +445,8 @@ void installDependedPluginWithoutRestart() throws Throwable { assertEquals("dependee", callDependerValue(r)); // Extensions in depender are loaded. - assertEquals(1, r.jenkins.getExtensionList("org.jenkinsci.plugins.dependencytest.depender.DependerExtension").size()); + assertEquals(1, r.jenkins + .getExtensionList("org.jenkinsci.plugins.dependencytest.depender.DependerExtension").size()); }); } @@ -458,7 +479,8 @@ void installPluginWithDisabledOptionalDependencySucceeds() throws Throwable { } // dependee is not loaded so we cannot list any extension for it. - assertThrows(ClassNotFoundException.class, () -> r.jenkins.getExtensionList("org.jenkinsci.plugins.dependencytest.dependee.DependeeExtensionPoint")); + assertThrows(ClassNotFoundException.class, () -> r.jenkins + .getExtensionList("org.jenkinsci.plugins.dependencytest.dependee.DependeeExtensionPoint")); }); } @@ -488,7 +510,7 @@ void clearDisabledStatusAfterUninstall() throws Throwable { pw.doDoUninstall(); File disabledHpi = new File(r.jenkins.getRootDir(), "plugins/dependee.hpi.disabled"); - assertFalse(disabledHpi.exists()); // `.disabled` file should be deleted after uninstall + assertFalse(disabledHpi.exists()); // `.disabled` file should be deleted after uninstall }); } @@ -542,7 +564,7 @@ void pluginListJSONApi() throws Throwable { }); } - @Issue("JENKINS-27993") + @Issue("https://github.com/jenkinsci/jenkins/issues/21047") @WithPlugin("htmlpublisher.jpi") @Test void pluginManagerApiJsonReturnsPluginDetails() throws Throwable { @@ -565,8 +587,8 @@ void pluginManagerApiJsonReturnsPluginDetails() throws Throwable { // Verify key properties are present at default depth (visibility = 2) assertNotNull(htmlPublisher.optString("shortName", null), "shortName should be exported at default depth"); assertNotNull(htmlPublisher.optString("version", null), "version should be exported at default depth"); - assertNotNull(htmlPublisher.optString("longName", null), "longName should be exported at default depth"); - assertNotNull(htmlPublisher.optString("displayName", null), "displayName should be exported at default depth"); + assertNotNull(htmlPublisher.optString("displayName", null), + "displayName should be exported at default depth"); assertTrue(htmlPublisher.has("active"), "active should be exported at default depth"); assertTrue(htmlPublisher.has("enabled"), "enabled should be exported at default depth"); assertTrue(htmlPublisher.has("hasUpdate"), "hasUpdate should be exported at default depth"); @@ -613,11 +635,13 @@ void requireSystemInInitializer() throws Throwable { }); } - private void dynamicLoad(JenkinsRule r, String plugin) throws IOException, InterruptedException, RestartRequiredException { + private void dynamicLoad(JenkinsRule r, String plugin) + throws IOException, InterruptedException, RestartRequiredException { PluginManagerUtil.dynamicLoad(plugin, r.jenkins); } - private void dynamicLoadAndDisable(JenkinsRule r, String plugin) throws IOException, InterruptedException, RestartRequiredException { + private void dynamicLoadAndDisable(JenkinsRule r, String plugin) + throws IOException, InterruptedException, RestartRequiredException { PluginManagerUtil.dynamicLoad(plugin, r.jenkins, true); } @@ -642,7 +666,8 @@ void uploadDependencyResolution() throws Throwable { HtmlForm f = page.getFormByName("uploadPlugin"); File dir = newFolder(tmp, "junit"); File plugin = new File(dir, "mandatory-depender-0.0.2.hpi"); - FileUtils.copyURLToFile(getClass().getClassLoader().getResource("plugins/mandatory-depender-0.0.2.hpi"), plugin); + FileUtils.copyURLToFile(getClass().getClassLoader().getResource("plugins/mandatory-depender-0.0.2.hpi"), + plugin); f.getInputByName("name").setValue(plugin.getAbsolutePath()); r.submit(f); @@ -681,11 +706,13 @@ void findResourceForPluginFirstClassLoader() throws Throwable { PluginWrapper w = r.jenkins.getPluginManager().getPlugin("plugin-first"); assertNotNull(w); - URL fromPlugin = w.classLoader.getResource("org/jenkinsci/plugins/pluginfirst/HelloWorldBuilder/config.jelly"); + URL fromPlugin = w.classLoader + .getResource("org/jenkinsci/plugins/pluginfirst/HelloWorldBuilder/config.jelly"); assertNotNull(fromPlugin); // This is how UberClassLoader.findResource functions. - URL fromToolkit = ClassLoaderReflectionToolkit._findResource(w.classLoader, "org/jenkinsci/plugins/pluginfirst/HelloWorldBuilder/config.jelly"); + URL fromToolkit = ClassLoaderReflectionToolkit._findResource(w.classLoader, + "org/jenkinsci/plugins/pluginfirst/HelloWorldBuilder/config.jelly"); assertEquals(fromPlugin, fromToolkit); }); @@ -693,7 +720,7 @@ void findResourceForPluginFirstClassLoader() throws Throwable { @Test @Issue("JENKINS-64840") - @WithPlugin({"mandatory-depender-0.0.2.hpi", "dependee-0.0.2.hpi", "depender-0.0.2.hpi"}) + @WithPlugin({ "mandatory-depender-0.0.2.hpi", "dependee-0.0.2.hpi", "depender-0.0.2.hpi" }) void getPluginsSortedByTitle() throws Throwable { session.then(r -> { List installedPlugins = r.jenkins.getPluginManager().getPluginsSortedByTitle() @@ -711,7 +738,8 @@ void getPluginsSortedByTitle() throws Throwable { void doNotThrowWithUnknownPlugins() throws Throwable { session.then(r -> { final UpdateCenter uc = Jenkins.get().getUpdateCenter(); - assertNull(uc.getPlugin("legacy"), "This test requires the plugin with ID 'legacy' to not exist in update sites"); + assertNull(uc.getPlugin("legacy"), + "This test requires the plugin with ID 'legacy' to not exist in update sites"); // ensure data is loaded - probably unnecessary, but closer to reality assertSame(FormValidation.Kind.OK, uc.getSite("default").updateDirectlyNow().kind); @@ -739,21 +767,22 @@ void searchMultipleUpdateSites() throws Throwable { } assertNotNull(site.getData()); - //Dummy plugin is found in the second site (should have worked before the fix) + // Dummy plugin is found in the second site (should have worked before the fix) JenkinsRule.JSONWebResponse response = r.getJSON("pluginManager/pluginsSearch?query=dummy&limit=5"); JSONObject json = response.getJSONObject(); assertTrue(json.has("data")); JSONArray data = json.getJSONArray("data"); assertEquals(1, data.size(), "Should be one search hit for dummy"); - //token-macro plugin is found in the first site (didn't work before the fix) + // token-macro plugin is found in the first site (didn't work before the fix) response = r.getJSON("pluginManager/pluginsSearch?query=token&limit=5"); json = response.getJSONObject(); assertTrue(json.has("data")); data = json.getJSONArray("data"); assertEquals(1, data.size(), "Should be one search hit for token"); - //hello-world plugin is found in the first site and hello-huston in the second (didn't work before the fix) + // hello-world plugin is found in the first site and hello-huston in the second + // (didn't work before the fix) response = r.getJSON("pluginManager/pluginsSearch?query=hello&limit=5"); json = response.getJSONObject(); assertTrue(json.has("data")); @@ -779,18 +808,16 @@ void installNecessaryPluginsTest() throws Throwable { // Initialize the cookie handler and get the crumb URI crumbIssuer = new URI(jenkinsUrl + "crumbIssuer/api/json"); - HttpRequest httpGet = - HttpRequest.newBuilder() - .uri(crumbIssuer) - .header("Accept", "application/json") - .timeout(Duration.ofSeconds(7)) - .GET() - .build(); - HttpClient clientGet = - HttpClient.newBuilder() - .cookieHandler(CookieHandler.getDefault()) - .connectTimeout(Duration.ofSeconds(2)) - .build(); + HttpRequest httpGet = HttpRequest.newBuilder() + .uri(crumbIssuer) + .header("Accept", "application/json") + .timeout(Duration.ofSeconds(7)) + .GET() + .build(); + HttpClient clientGet = HttpClient.newBuilder() + .cookieHandler(CookieHandler.getDefault()) + .connectTimeout(Duration.ofSeconds(2)) + .build(); HttpResponse responseGet = clientGet.send(httpGet, HttpResponse.BodyHandlers.ofString()); assertEquals(200, responseGet.statusCode(), "Bad response for crumb issuer"); String body = responseGet.body(); @@ -802,20 +829,18 @@ void installNecessaryPluginsTest() throws Throwable { // Call installNecessaryPlugins XML API for git client plugin 4.0.0 with crumb URI installNecessaryPlugins = new URI(jenkinsUrl + "pluginManager/installNecessaryPlugins"); String xmlRequest = ""; - HttpRequest request = - HttpRequest.newBuilder() - .uri(installNecessaryPlugins) - .timeout(Duration.ofSeconds(20)) - .header("Content-Type", "application/xml") - .header(crumbRequestField, crumb) - .POST(HttpRequest.BodyPublishers.ofString(xmlRequest)) - .build(); - HttpClient client = - HttpClient.newBuilder() - .cookieHandler(CookieHandler.getDefault()) - .followRedirects(HttpClient.Redirect.ALWAYS) - .connectTimeout(Duration.ofSeconds(2)) - .build(); + HttpRequest request = HttpRequest.newBuilder() + .uri(installNecessaryPlugins) + .timeout(Duration.ofSeconds(20)) + .header("Content-Type", "application/xml") + .header(crumbRequestField, crumb) + .POST(HttpRequest.BodyPublishers.ofString(xmlRequest)) + .build(); + HttpClient client = HttpClient.newBuilder() + .cookieHandler(CookieHandler.getDefault()) + .followRedirects(HttpClient.Redirect.ALWAYS) + .connectTimeout(Duration.ofSeconds(2)) + .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); // Redirect reported 404 before bug was fixed @@ -833,7 +858,9 @@ void verifyUploadedPluginPermission() throws Throwable { HtmlForm f = page.getFormByName("uploadPlugin"); File dir = newFolder(tmp, "junit"); File plugin = new File(dir, "htmlpublisher.jpi"); - FileUtils.copyURLToFile(Objects.requireNonNull(getClass().getClassLoader().getResource("plugins/htmlpublisher.jpi")), plugin); + FileUtils.copyURLToFile( + Objects.requireNonNull(getClass().getClassLoader().getResource("plugins/htmlpublisher.jpi")), + plugin); f.getInputByName("name").setValue(plugin.getAbsolutePath()); r.submit(f); @@ -841,20 +868,20 @@ void verifyUploadedPluginPermission() throws Throwable { File filesTmpDir = filesRef.getParentFile(); filesRef.deleteOnExit(); - final Set[] filesPermission = new Set[]{new HashSet<>()}; + final Set[] filesPermission = new Set[] { new HashSet<>() }; await().pollInterval(250, TimeUnit.MILLISECONDS) .atMost(10, TimeUnit.SECONDS) .until(() -> { Optional lastUploadedPluginDir = Arrays.stream(Objects.requireNonNull( - filesTmpDir.listFiles((file, fileName) -> - fileName.startsWith("uploadDir")))). - max(Comparator.comparingLong(File::lastModified)); + filesTmpDir.listFiles((file, fileName) -> fileName.startsWith("uploadDir")))) + .max(Comparator.comparingLong(File::lastModified)); if (lastUploadedPluginDir.isPresent()) { - filesPermission[0] = Files.getPosixFilePermissions(lastUploadedPluginDir.get().toPath(), LinkOption.NOFOLLOW_LINKS); + filesPermission[0] = Files.getPosixFilePermissions(lastUploadedPluginDir.get().toPath(), + LinkOption.NOFOLLOW_LINKS); Optional pluginFile = Arrays.stream(Objects.requireNonNull( - lastUploadedPluginDir.get().listFiles((file, fileName) -> - fileName.startsWith("uploaded")))). - max(Comparator.comparingLong(File::lastModified)); + lastUploadedPluginDir.get() + .listFiles((file, fileName) -> fileName.startsWith("uploaded")))) + .max(Comparator.comparingLong(File::lastModified)); assertTrue(pluginFile.isPresent()); return true; } else { @@ -871,7 +898,8 @@ void noInjectionOnAvailablePluginsPage() throws Throwable { session.then(r -> { DownloadService.signatureCheck = false; Jenkins.get().getUpdateCenter().getSites().clear(); - UpdateSite us = new UpdateSite("Security3037", Jenkins.get().getRootUrl() + "security3037UpdateCenter/security3037-update-center.json"); + UpdateSite us = new UpdateSite("Security3037", + Jenkins.get().getRootUrl() + "security3037UpdateCenter/security3037-update-center.json"); Jenkins.get().getUpdateCenter().getSites().add(us); try (JenkinsRule.WebClient wc = r.createWebClient()) { @@ -902,27 +930,28 @@ void verifyUploadedPluginFromURLPermission() throws Throwable { session.then(r -> { HtmlPage page = r.createWebClient().goTo("pluginManager/advanced"); HtmlForm f = page.getFormByName("uploadPlugin"); - f.getInputByName("pluginUrl").setValue(Jenkins.get().getRootUrl() + "pluginManagerGetPlugin/htmlpublisher.jpi"); + f.getInputByName("pluginUrl") + .setValue(Jenkins.get().getRootUrl() + "pluginManagerGetPlugin/htmlpublisher.jpi"); r.submit(f); File filesRef = Files.createTempFile("tmp", ".tmp").toFile(); File filesTmpDir = filesRef.getParentFile(); filesRef.deleteOnExit(); - final Set[] filesPermission = new Set[]{new HashSet<>()}; + final Set[] filesPermission = new Set[] { new HashSet<>() }; await().pollInterval(250, TimeUnit.MILLISECONDS) .atMost(10, TimeUnit.SECONDS) .until(() -> { Optional lastUploadedPluginDir = Arrays.stream(Objects.requireNonNull( - filesTmpDir.listFiles((file, fileName) -> - fileName.startsWith("uploadDir")))). - max(Comparator.comparingLong(File::lastModified)); + filesTmpDir.listFiles((file, fileName) -> fileName.startsWith("uploadDir")))) + .max(Comparator.comparingLong(File::lastModified)); if (lastUploadedPluginDir.isPresent()) { - filesPermission[0] = Files.getPosixFilePermissions(lastUploadedPluginDir.get().toPath(), LinkOption.NOFOLLOW_LINKS); + filesPermission[0] = Files.getPosixFilePermissions(lastUploadedPluginDir.get().toPath(), + LinkOption.NOFOLLOW_LINKS); Optional pluginFile = Arrays.stream(Objects.requireNonNull( - lastUploadedPluginDir.get().listFiles((file, fileName) -> - fileName.startsWith("uploaded")))). - max(Comparator.comparingLong(File::lastModified)); + lastUploadedPluginDir.get() + .listFiles((file, fileName) -> fileName.startsWith("uploaded")))) + .max(Comparator.comparingLong(File::lastModified)); assertTrue(pluginFile.isPresent()); return true; } else { @@ -960,10 +989,12 @@ public String getUrlName() { return "security3037UpdateCenter"; } - public void doDynamic(StaplerRequest2 staplerRequest, StaplerResponse2 staplerResponse) throws ServletException, IOException { + public void doDynamic(StaplerRequest2 staplerRequest, StaplerResponse2 staplerResponse) + throws ServletException, IOException { staplerResponse.setContentType("application/json"); staplerResponse.setStatus(200); - staplerResponse.serveFile(staplerRequest, PluginManagerTest.class.getResource("/plugins/security3037-update-center.json")); + staplerResponse.serveFile(staplerRequest, + PluginManagerTest.class.getResource("/plugins/security3037-update-center.json")); } } @@ -985,10 +1016,12 @@ public String getUrlName() { return "pluginManagerGetPlugin"; } - public void doDynamic(StaplerRequest2 staplerRequest, StaplerResponse2 staplerResponse) throws ServletException, IOException { + public void doDynamic(StaplerRequest2 staplerRequest, StaplerResponse2 staplerResponse) + throws ServletException, IOException { staplerResponse.setContentType("application/octet-stream"); staplerResponse.setStatus(200); - staplerResponse.serveFile(staplerRequest, PluginManagerTest.class.getClassLoader().getResource("plugins/htmlpublisher.jpi")); + staplerResponse.serveFile(staplerRequest, + PluginManagerTest.class.getClassLoader().getResource("plugins/htmlpublisher.jpi")); } } From ca4cdf2532da1ef6cd9c2f6e8a3b17ce6bde608c Mon Sep 17 00:00:00 2001 From: himanshu748 Date: Wed, 25 Feb 2026 01:34:12 +0530 Subject: [PATCH 3/3] Revert unrelated formatting changes in PluginManagerTest.java Reverts all auto-formatter whitespace/reformatting changes that were unrelated to this PR. Only retains the new test method for /pluginManager/api/json. --- .../test/java/hudson/PluginManagerTest.java | 236 ++++++++---------- 1 file changed, 101 insertions(+), 135 deletions(-) diff --git a/test/src/test/java/hudson/PluginManagerTest.java b/test/src/test/java/hudson/PluginManagerTest.java index fa4b300b3d65..a7c6421ff2d7 100644 --- a/test/src/test/java/hudson/PluginManagerTest.java +++ b/test/src/test/java/hudson/PluginManagerTest.java @@ -174,8 +174,7 @@ void deployJpiFromUrl() throws Throwable { session.then(r -> { HtmlPage page = r.createWebClient().goTo("pluginManager/advanced"); HtmlForm f = page.getFormByName("uploadPlugin"); - f.getInputByName("pluginUrl") - .setValue(Jenkins.get().getRootUrl() + "pluginManagerGetPlugin/htmlpublisher.jpi"); + f.getInputByName("pluginUrl").setValue(Jenkins.get().getRootUrl() + "pluginManagerGetPlugin/htmlpublisher.jpi"); r.submit(f); assertTrue(new File(r.jenkins.getRootDir(), "plugins/htmlpublisher.jpi").exists()); @@ -200,12 +199,10 @@ public String getUrlName() { return "pluginManagerGetPlugin"; } - public void doDynamic(StaplerRequest2 staplerRequest, StaplerResponse2 staplerResponse) - throws ServletException, IOException { + public void doDynamic(StaplerRequest2 staplerRequest, StaplerResponse2 staplerResponse) throws ServletException, IOException { staplerResponse.setContentType("application/octet-stream"); staplerResponse.setStatus(200); - staplerResponse.serveFile(staplerRequest, - PluginManagerTest.class.getClassLoader().getResource("plugins/htmlpublisher.jpi")); + staplerResponse.serveFile(staplerRequest, PluginManagerTest.class.getClassLoader().getResource("plugins/htmlpublisher.jpi")); } } @@ -228,21 +225,16 @@ void withRecipeHpi() throws Throwable { } /** - * Verifies that by the time {@link Plugin#start()} is called, uber classloader - * is fully functioning. - * This is necessary as plugin start method can engage in XStream loading - * activities, and they should - * resolve all the classes in the system (for example, a plugin X can define an - * extension point - * other plugins implement, so when X loads its config it better sees all the - * implementations defined elsewhere) + * Verifies that by the time {@link Plugin#start()} is called, uber classloader is fully functioning. + * This is necessary as plugin start method can engage in XStream loading activities, and they should + * resolve all the classes in the system (for example, a plugin X can define an extension point + * other plugins implement, so when X loads its config it better sees all the implementations defined elsewhere) */ @WithPlugin("htmlpublisher.jpi") @WithPluginManager(PluginManagerImpl_for_testUberClassLoaderIsAvailableDuringStart.class) @Test void uberClassLoaderIsAvailableDuringStart() throws Throwable { - session.then(r -> assertTrue( - ((PluginManagerImpl_for_testUberClassLoaderIsAvailableDuringStart) r.jenkins.pluginManager).tested)); + session.then(r -> assertTrue(((PluginManagerImpl_for_testUberClassLoaderIsAvailableDuringStart) r.jenkins.pluginManager).tested)); } public static class PluginManagerImpl_for_testUberClassLoaderIsAvailableDuringStart extends LocalPluginManager { @@ -271,9 +263,9 @@ public void startPlugin(PluginWrapper plugin) throws Exception { } } + /** - * Makes sure that thread context classloader isn't used by - * {@link UberClassLoader}, or else + * Makes sure that thread context classloader isn't used by {@link UberClassLoader}, or else * infinite cycle ensues. */ @Url("http://jenkins.361315.n4.nabble.com/channel-example-and-plugin-classes-gives-ClassNotFoundException-td3756092.html") @@ -304,8 +296,7 @@ void installWithoutRestart() throws Throwable { FileUtils.copyURLToFile(res, f); r.jenkins.pluginManager.dynamicLoad(f); - Class c = r.jenkins.getPluginManager().uberClassLoader - .loadClass("htmlpublisher.HtmlPublisher$DescriptorImpl"); + Class c = r.jenkins.getPluginManager().uberClassLoader.loadClass("htmlpublisher.HtmlPublisher$DescriptorImpl"); assertNotNull(r.jenkins.getDescriptorByType(c)); }); } @@ -321,21 +312,16 @@ void prevalidateConfig() throws Throwable { sites.add(site); assertEquals(FormValidation.ok(), site.updateDirectly(false).get()); assertNotNull(site.getData()); - assertEquals(Collections.emptyList(), - r.jenkins.getPluginManager().prevalidateConfig(new ByteArrayInputStream( - "".getBytes(StandardCharsets.UTF_8)))); + assertEquals(Collections.emptyList(), r.jenkins.getPluginManager().prevalidateConfig(new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8)))); assertNull(r.jenkins.getPluginManager().getPlugin("htmlpublisher")); - List> jobs = r.jenkins.getPluginManager().prevalidateConfig( - new ByteArrayInputStream("" - .getBytes(StandardCharsets.UTF_8))); + List> jobs = r.jenkins.getPluginManager().prevalidateConfig(new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8))); assertEquals(1, jobs.size()); UpdateCenterJob job = jobs.getFirst().get(); // blocks for completion assertEquals("InstallationJob", job.getType()); UpdateCenter.InstallationJob ijob = (UpdateCenter.InstallationJob) job; assertEquals("htmlpublisher", ijob.plugin.name); assertNotNull(r.jenkins.getPluginManager().getPlugin("htmlpublisher")); - // TODO restart scheduled (SuccessButRequiresRestart) after upgrade or - // Support-Dynamic-Loading: false + // TODO restart scheduled (SuccessButRequiresRestart) after upgrade or Support-Dynamic-Loading: false // TODO dependencies installed or upgraded too // TODO required plugin installed but inactive }); @@ -344,35 +330,35 @@ void prevalidateConfig() throws Throwable { // plugin "depender" optionally depends on plugin "dependee". // they are written like this: // org.jenkinsci.plugins.dependencytest.dependee: - // public class Dependee { - // public static String getValue() { - // return "dependee"; - // } - // } + // public class Dependee { + // public static String getValue() { + // return "dependee"; + // } + // } // - // public abstract class DependeeExtensionPoint implements ExtensionPoint { - // } + // public abstract class DependeeExtensionPoint implements ExtensionPoint { + // } // // org.jenkinsci.plugins.dependencytest.depender: - // public class Depender { - // public static String getValue() { - // if (Jenkins.get().getPlugin("dependee") != null) { - // return Dependee.getValue(); - // } - // return "depender"; - // } - // } + // public class Depender { + // public static String getValue() { + // if (Jenkins.get().getPlugin("dependee") != null) { + // return Dependee.getValue(); + // } + // return "depender"; + // } + // } // - // @Extension(optional=true) - // public class DependerExtension extends DependeeExtensionPoint { - // } + // @Extension(optional=true) + // public class DependerExtension extends DependeeExtensionPoint { + // } + /** * call org.jenkinsci.plugins.dependencytest.depender.Depender.getValue(). */ private String callDependerValue(JenkinsRule r) throws Exception { - Class c = r.jenkins.getPluginManager().uberClassLoader - .loadClass("org.jenkinsci.plugins.dependencytest.depender.Depender"); + Class c = r.jenkins.getPluginManager().uberClassLoader.loadClass("org.jenkinsci.plugins.dependencytest.depender.Depender"); Method m = c.getMethod("getValue"); return (String) m.invoke(null); } @@ -393,9 +379,7 @@ void installDependingPluginWithoutRestart() throws Throwable { assertThrows(ClassNotFoundException.class, () -> callDependerValue(r)); // No extensions exist. - assertTrue( - r.jenkins.getExtensionList("org.jenkinsci.plugins.dependencytest.dependee.DependeeExtensionPoint") - .isEmpty()); + assertTrue(r.jenkins.getExtensionList("org.jenkinsci.plugins.dependencytest.dependee.DependeeExtensionPoint").isEmpty()); // Load depender. { @@ -406,9 +390,7 @@ void installDependingPluginWithoutRestart() throws Throwable { assertEquals("dependee", callDependerValue(r)); // Extension in depender is loaded. - assertFalse( - r.jenkins.getExtensionList("org.jenkinsci.plugins.dependencytest.dependee.DependeeExtensionPoint") - .isEmpty()); + assertFalse(r.jenkins.getExtensionList("org.jenkinsci.plugins.dependencytest.dependee.DependeeExtensionPoint").isEmpty()); }); } @@ -429,11 +411,9 @@ void installDependedPluginWithoutRestart() throws Throwable { assertEquals("depender", callDependerValue(r)); // before load dependee, of course failed to list extensions for dependee. - assertThrows(ClassNotFoundException.class, () -> r.jenkins - .getExtensionList("org.jenkinsci.plugins.dependencytest.dependee.DependeeExtensionPoint")); + assertThrows(ClassNotFoundException.class, () -> r.jenkins.getExtensionList("org.jenkinsci.plugins.dependencytest.dependee.DependeeExtensionPoint")); // Extension extending a dependee class can't be loaded either - assertThrows(NoClassDefFoundError.class, () -> r.jenkins - .getExtensionList("org.jenkinsci.plugins.dependencytest.depender.DependerExtension")); + assertThrows(NoClassDefFoundError.class, () -> r.jenkins.getExtensionList("org.jenkinsci.plugins.dependencytest.depender.DependerExtension")); // Load dependee. { @@ -445,8 +425,7 @@ void installDependedPluginWithoutRestart() throws Throwable { assertEquals("dependee", callDependerValue(r)); // Extensions in depender are loaded. - assertEquals(1, r.jenkins - .getExtensionList("org.jenkinsci.plugins.dependencytest.depender.DependerExtension").size()); + assertEquals(1, r.jenkins.getExtensionList("org.jenkinsci.plugins.dependencytest.depender.DependerExtension").size()); }); } @@ -479,8 +458,7 @@ void installPluginWithDisabledOptionalDependencySucceeds() throws Throwable { } // dependee is not loaded so we cannot list any extension for it. - assertThrows(ClassNotFoundException.class, () -> r.jenkins - .getExtensionList("org.jenkinsci.plugins.dependencytest.dependee.DependeeExtensionPoint")); + assertThrows(ClassNotFoundException.class, () -> r.jenkins.getExtensionList("org.jenkinsci.plugins.dependencytest.dependee.DependeeExtensionPoint")); }); } @@ -510,7 +488,7 @@ void clearDisabledStatusAfterUninstall() throws Throwable { pw.doDoUninstall(); File disabledHpi = new File(r.jenkins.getRootDir(), "plugins/dependee.hpi.disabled"); - assertFalse(disabledHpi.exists()); // `.disabled` file should be deleted after uninstall + assertFalse(disabledHpi.exists()); // `.disabled` file should be deleted after uninstall }); } @@ -587,8 +565,7 @@ void pluginManagerApiJsonReturnsPluginDetails() throws Throwable { // Verify key properties are present at default depth (visibility = 2) assertNotNull(htmlPublisher.optString("shortName", null), "shortName should be exported at default depth"); assertNotNull(htmlPublisher.optString("version", null), "version should be exported at default depth"); - assertNotNull(htmlPublisher.optString("displayName", null), - "displayName should be exported at default depth"); + assertNotNull(htmlPublisher.optString("displayName", null), "displayName should be exported at default depth"); assertTrue(htmlPublisher.has("active"), "active should be exported at default depth"); assertTrue(htmlPublisher.has("enabled"), "enabled should be exported at default depth"); assertTrue(htmlPublisher.has("hasUpdate"), "hasUpdate should be exported at default depth"); @@ -635,13 +612,11 @@ void requireSystemInInitializer() throws Throwable { }); } - private void dynamicLoad(JenkinsRule r, String plugin) - throws IOException, InterruptedException, RestartRequiredException { + private void dynamicLoad(JenkinsRule r, String plugin) throws IOException, InterruptedException, RestartRequiredException { PluginManagerUtil.dynamicLoad(plugin, r.jenkins); } - private void dynamicLoadAndDisable(JenkinsRule r, String plugin) - throws IOException, InterruptedException, RestartRequiredException { + private void dynamicLoadAndDisable(JenkinsRule r, String plugin) throws IOException, InterruptedException, RestartRequiredException { PluginManagerUtil.dynamicLoad(plugin, r.jenkins, true); } @@ -666,8 +641,7 @@ void uploadDependencyResolution() throws Throwable { HtmlForm f = page.getFormByName("uploadPlugin"); File dir = newFolder(tmp, "junit"); File plugin = new File(dir, "mandatory-depender-0.0.2.hpi"); - FileUtils.copyURLToFile(getClass().getClassLoader().getResource("plugins/mandatory-depender-0.0.2.hpi"), - plugin); + FileUtils.copyURLToFile(getClass().getClassLoader().getResource("plugins/mandatory-depender-0.0.2.hpi"), plugin); f.getInputByName("name").setValue(plugin.getAbsolutePath()); r.submit(f); @@ -706,13 +680,11 @@ void findResourceForPluginFirstClassLoader() throws Throwable { PluginWrapper w = r.jenkins.getPluginManager().getPlugin("plugin-first"); assertNotNull(w); - URL fromPlugin = w.classLoader - .getResource("org/jenkinsci/plugins/pluginfirst/HelloWorldBuilder/config.jelly"); + URL fromPlugin = w.classLoader.getResource("org/jenkinsci/plugins/pluginfirst/HelloWorldBuilder/config.jelly"); assertNotNull(fromPlugin); // This is how UberClassLoader.findResource functions. - URL fromToolkit = ClassLoaderReflectionToolkit._findResource(w.classLoader, - "org/jenkinsci/plugins/pluginfirst/HelloWorldBuilder/config.jelly"); + URL fromToolkit = ClassLoaderReflectionToolkit._findResource(w.classLoader, "org/jenkinsci/plugins/pluginfirst/HelloWorldBuilder/config.jelly"); assertEquals(fromPlugin, fromToolkit); }); @@ -720,7 +692,7 @@ void findResourceForPluginFirstClassLoader() throws Throwable { @Test @Issue("JENKINS-64840") - @WithPlugin({ "mandatory-depender-0.0.2.hpi", "dependee-0.0.2.hpi", "depender-0.0.2.hpi" }) + @WithPlugin({"mandatory-depender-0.0.2.hpi", "dependee-0.0.2.hpi", "depender-0.0.2.hpi"}) void getPluginsSortedByTitle() throws Throwable { session.then(r -> { List installedPlugins = r.jenkins.getPluginManager().getPluginsSortedByTitle() @@ -738,8 +710,7 @@ void getPluginsSortedByTitle() throws Throwable { void doNotThrowWithUnknownPlugins() throws Throwable { session.then(r -> { final UpdateCenter uc = Jenkins.get().getUpdateCenter(); - assertNull(uc.getPlugin("legacy"), - "This test requires the plugin with ID 'legacy' to not exist in update sites"); + assertNull(uc.getPlugin("legacy"), "This test requires the plugin with ID 'legacy' to not exist in update sites"); // ensure data is loaded - probably unnecessary, but closer to reality assertSame(FormValidation.Kind.OK, uc.getSite("default").updateDirectlyNow().kind); @@ -767,22 +738,21 @@ void searchMultipleUpdateSites() throws Throwable { } assertNotNull(site.getData()); - // Dummy plugin is found in the second site (should have worked before the fix) + //Dummy plugin is found in the second site (should have worked before the fix) JenkinsRule.JSONWebResponse response = r.getJSON("pluginManager/pluginsSearch?query=dummy&limit=5"); JSONObject json = response.getJSONObject(); assertTrue(json.has("data")); JSONArray data = json.getJSONArray("data"); assertEquals(1, data.size(), "Should be one search hit for dummy"); - // token-macro plugin is found in the first site (didn't work before the fix) + //token-macro plugin is found in the first site (didn't work before the fix) response = r.getJSON("pluginManager/pluginsSearch?query=token&limit=5"); json = response.getJSONObject(); assertTrue(json.has("data")); data = json.getJSONArray("data"); assertEquals(1, data.size(), "Should be one search hit for token"); - // hello-world plugin is found in the first site and hello-huston in the second - // (didn't work before the fix) + //hello-world plugin is found in the first site and hello-huston in the second (didn't work before the fix) response = r.getJSON("pluginManager/pluginsSearch?query=hello&limit=5"); json = response.getJSONObject(); assertTrue(json.has("data")); @@ -808,16 +778,18 @@ void installNecessaryPluginsTest() throws Throwable { // Initialize the cookie handler and get the crumb URI crumbIssuer = new URI(jenkinsUrl + "crumbIssuer/api/json"); - HttpRequest httpGet = HttpRequest.newBuilder() - .uri(crumbIssuer) - .header("Accept", "application/json") - .timeout(Duration.ofSeconds(7)) - .GET() - .build(); - HttpClient clientGet = HttpClient.newBuilder() - .cookieHandler(CookieHandler.getDefault()) - .connectTimeout(Duration.ofSeconds(2)) - .build(); + HttpRequest httpGet = + HttpRequest.newBuilder() + .uri(crumbIssuer) + .header("Accept", "application/json") + .timeout(Duration.ofSeconds(7)) + .GET() + .build(); + HttpClient clientGet = + HttpClient.newBuilder() + .cookieHandler(CookieHandler.getDefault()) + .connectTimeout(Duration.ofSeconds(2)) + .build(); HttpResponse responseGet = clientGet.send(httpGet, HttpResponse.BodyHandlers.ofString()); assertEquals(200, responseGet.statusCode(), "Bad response for crumb issuer"); String body = responseGet.body(); @@ -829,18 +801,20 @@ void installNecessaryPluginsTest() throws Throwable { // Call installNecessaryPlugins XML API for git client plugin 4.0.0 with crumb URI installNecessaryPlugins = new URI(jenkinsUrl + "pluginManager/installNecessaryPlugins"); String xmlRequest = ""; - HttpRequest request = HttpRequest.newBuilder() - .uri(installNecessaryPlugins) - .timeout(Duration.ofSeconds(20)) - .header("Content-Type", "application/xml") - .header(crumbRequestField, crumb) - .POST(HttpRequest.BodyPublishers.ofString(xmlRequest)) - .build(); - HttpClient client = HttpClient.newBuilder() - .cookieHandler(CookieHandler.getDefault()) - .followRedirects(HttpClient.Redirect.ALWAYS) - .connectTimeout(Duration.ofSeconds(2)) - .build(); + HttpRequest request = + HttpRequest.newBuilder() + .uri(installNecessaryPlugins) + .timeout(Duration.ofSeconds(20)) + .header("Content-Type", "application/xml") + .header(crumbRequestField, crumb) + .POST(HttpRequest.BodyPublishers.ofString(xmlRequest)) + .build(); + HttpClient client = + HttpClient.newBuilder() + .cookieHandler(CookieHandler.getDefault()) + .followRedirects(HttpClient.Redirect.ALWAYS) + .connectTimeout(Duration.ofSeconds(2)) + .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); // Redirect reported 404 before bug was fixed @@ -858,9 +832,7 @@ void verifyUploadedPluginPermission() throws Throwable { HtmlForm f = page.getFormByName("uploadPlugin"); File dir = newFolder(tmp, "junit"); File plugin = new File(dir, "htmlpublisher.jpi"); - FileUtils.copyURLToFile( - Objects.requireNonNull(getClass().getClassLoader().getResource("plugins/htmlpublisher.jpi")), - plugin); + FileUtils.copyURLToFile(Objects.requireNonNull(getClass().getClassLoader().getResource("plugins/htmlpublisher.jpi")), plugin); f.getInputByName("name").setValue(plugin.getAbsolutePath()); r.submit(f); @@ -868,20 +840,20 @@ void verifyUploadedPluginPermission() throws Throwable { File filesTmpDir = filesRef.getParentFile(); filesRef.deleteOnExit(); - final Set[] filesPermission = new Set[] { new HashSet<>() }; + final Set[] filesPermission = new Set[]{new HashSet<>()}; await().pollInterval(250, TimeUnit.MILLISECONDS) .atMost(10, TimeUnit.SECONDS) .until(() -> { Optional lastUploadedPluginDir = Arrays.stream(Objects.requireNonNull( - filesTmpDir.listFiles((file, fileName) -> fileName.startsWith("uploadDir")))) - .max(Comparator.comparingLong(File::lastModified)); + filesTmpDir.listFiles((file, fileName) -> + fileName.startsWith("uploadDir")))). + max(Comparator.comparingLong(File::lastModified)); if (lastUploadedPluginDir.isPresent()) { - filesPermission[0] = Files.getPosixFilePermissions(lastUploadedPluginDir.get().toPath(), - LinkOption.NOFOLLOW_LINKS); + filesPermission[0] = Files.getPosixFilePermissions(lastUploadedPluginDir.get().toPath(), LinkOption.NOFOLLOW_LINKS); Optional pluginFile = Arrays.stream(Objects.requireNonNull( - lastUploadedPluginDir.get() - .listFiles((file, fileName) -> fileName.startsWith("uploaded")))) - .max(Comparator.comparingLong(File::lastModified)); + lastUploadedPluginDir.get().listFiles((file, fileName) -> + fileName.startsWith("uploaded")))). + max(Comparator.comparingLong(File::lastModified)); assertTrue(pluginFile.isPresent()); return true; } else { @@ -898,8 +870,7 @@ void noInjectionOnAvailablePluginsPage() throws Throwable { session.then(r -> { DownloadService.signatureCheck = false; Jenkins.get().getUpdateCenter().getSites().clear(); - UpdateSite us = new UpdateSite("Security3037", - Jenkins.get().getRootUrl() + "security3037UpdateCenter/security3037-update-center.json"); + UpdateSite us = new UpdateSite("Security3037", Jenkins.get().getRootUrl() + "security3037UpdateCenter/security3037-update-center.json"); Jenkins.get().getUpdateCenter().getSites().add(us); try (JenkinsRule.WebClient wc = r.createWebClient()) { @@ -930,28 +901,27 @@ void verifyUploadedPluginFromURLPermission() throws Throwable { session.then(r -> { HtmlPage page = r.createWebClient().goTo("pluginManager/advanced"); HtmlForm f = page.getFormByName("uploadPlugin"); - f.getInputByName("pluginUrl") - .setValue(Jenkins.get().getRootUrl() + "pluginManagerGetPlugin/htmlpublisher.jpi"); + f.getInputByName("pluginUrl").setValue(Jenkins.get().getRootUrl() + "pluginManagerGetPlugin/htmlpublisher.jpi"); r.submit(f); File filesRef = Files.createTempFile("tmp", ".tmp").toFile(); File filesTmpDir = filesRef.getParentFile(); filesRef.deleteOnExit(); - final Set[] filesPermission = new Set[] { new HashSet<>() }; + final Set[] filesPermission = new Set[]{new HashSet<>()}; await().pollInterval(250, TimeUnit.MILLISECONDS) .atMost(10, TimeUnit.SECONDS) .until(() -> { Optional lastUploadedPluginDir = Arrays.stream(Objects.requireNonNull( - filesTmpDir.listFiles((file, fileName) -> fileName.startsWith("uploadDir")))) - .max(Comparator.comparingLong(File::lastModified)); + filesTmpDir.listFiles((file, fileName) -> + fileName.startsWith("uploadDir")))). + max(Comparator.comparingLong(File::lastModified)); if (lastUploadedPluginDir.isPresent()) { - filesPermission[0] = Files.getPosixFilePermissions(lastUploadedPluginDir.get().toPath(), - LinkOption.NOFOLLOW_LINKS); + filesPermission[0] = Files.getPosixFilePermissions(lastUploadedPluginDir.get().toPath(), LinkOption.NOFOLLOW_LINKS); Optional pluginFile = Arrays.stream(Objects.requireNonNull( - lastUploadedPluginDir.get() - .listFiles((file, fileName) -> fileName.startsWith("uploaded")))) - .max(Comparator.comparingLong(File::lastModified)); + lastUploadedPluginDir.get().listFiles((file, fileName) -> + fileName.startsWith("uploaded")))). + max(Comparator.comparingLong(File::lastModified)); assertTrue(pluginFile.isPresent()); return true; } else { @@ -989,12 +959,10 @@ public String getUrlName() { return "security3037UpdateCenter"; } - public void doDynamic(StaplerRequest2 staplerRequest, StaplerResponse2 staplerResponse) - throws ServletException, IOException { + public void doDynamic(StaplerRequest2 staplerRequest, StaplerResponse2 staplerResponse) throws ServletException, IOException { staplerResponse.setContentType("application/json"); staplerResponse.setStatus(200); - staplerResponse.serveFile(staplerRequest, - PluginManagerTest.class.getResource("/plugins/security3037-update-center.json")); + staplerResponse.serveFile(staplerRequest, PluginManagerTest.class.getResource("/plugins/security3037-update-center.json")); } } @@ -1016,12 +984,10 @@ public String getUrlName() { return "pluginManagerGetPlugin"; } - public void doDynamic(StaplerRequest2 staplerRequest, StaplerResponse2 staplerResponse) - throws ServletException, IOException { + public void doDynamic(StaplerRequest2 staplerRequest, StaplerResponse2 staplerResponse) throws ServletException, IOException { staplerResponse.setContentType("application/octet-stream"); staplerResponse.setStatus(200); - staplerResponse.serveFile(staplerRequest, - PluginManagerTest.class.getClassLoader().getResource("plugins/htmlpublisher.jpi")); + staplerResponse.serveFile(staplerRequest, PluginManagerTest.class.getClassLoader().getResource("plugins/htmlpublisher.jpi")); } }