Skip to content

Commit

Permalink
[JENKINS-74964] Descriptor#newInstanceImpl Linkage error handling tes…
Browse files Browse the repository at this point in the history
…t cases
  • Loading branch information
Priya-CB committed Dec 13, 2024
1 parent 9944fa2 commit fe5d266
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@
import hudson.model.User;
import hudson.security.AccessControlled;
import hudson.security.Permission;
import hudson.util.HttpResponses;

import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
Expand Down Expand Up @@ -633,17 +633,13 @@ public JSONObject doAddCredentials(StaplerRequest2 req, StaplerResponse2 rsp) th
*/
Throwable rootCause = ExceptionUtils.getRootCause(e);
if (rootCause instanceof IOException || rootCause instanceof IllegalArgumentException

Check warning on line 635 in src/main/java/com/cloudbees/plugins/credentials/CredentialsSelectHelper.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 635 is only partially covered, one branch is missing
|| rootCause instanceof IllegalStateException) {
|| rootCause instanceof GeneralSecurityException) {
LOGGER.log(Level.WARNING, "Failed to create Credentials", e);
return new JSONObject().element("message", rootCause.getMessage()).element("notificationType",
"ERROR");
}
throw e;

Check warning on line 641 in src/main/java/com/cloudbees/plugins/credentials/CredentialsSelectHelper.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 641 is not covered by tests
} catch (IOException | IllegalArgumentException | IllegalStateException |
HttpResponses.HttpResponseException e) {
LOGGER.log(Level.WARNING, "Failed to create Credentials", e);
return new JSONObject().element("message", e.getMessage()).element("notificationType", "ERROR");
}
}
if (credentialsWereAdded) {
return new JSONObject()
.element("message", "Credentials created")
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/lib/credentials/select/select.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ window.credentials.addSubmit = function (_) {
.catch((e) => {
// notificationBar.show(...) with logging ID could be handy here?
console.error("Could not add credentials:", e);
window.notificationBar.show("Credentials creation failed.", window.notificationBar["ERROR"]);
window.notificationBar.show("Credentials creation failed", window.notificationBar["ERROR"]);
})
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@

import com.cloudbees.plugins.credentials.common.UsernamePasswordCredentials;
import com.cloudbees.plugins.credentials.impl.CertificateCredentialsImpl;
import com.cloudbees.plugins.credentials.impl.CertificateCredentialsImplTest;

import hudson.model.UnprotectedRootAction;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import net.sf.json.JSONObject;
import org.apache.commons.io.IOUtils;
import org.hamcrest.Matchers;
import org.htmlunit.Page;
import org.htmlunit.html.DomNode;
Expand All @@ -23,6 +27,7 @@
import org.htmlunit.html.HtmlOption;
import org.htmlunit.html.HtmlPage;
import org.htmlunit.html.HtmlRadioButtonInput;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.Issue;
Expand All @@ -33,6 +38,21 @@ public class CredentialsSelectHelperTest {
@Rule
public JenkinsRule j = new JenkinsRule();

private String pemCert;
private String pemKey;

private static final String VALID_PASSWORD = "password";
private static final String INVALID_PASSWORD = "bla";

@Before
public void setup() throws IOException {
pemCert = IOUtils.toString(CertificateCredentialsImplTest.class.getResource("certs.pem"),
StandardCharsets.UTF_8);
pemKey = IOUtils.toString(CertificateCredentialsImplTest.class.getResource("key.pem"),
StandardCharsets.UTF_8);
}


@Test
public void doAddCredentialsFromPopupWorksAsExpected() throws Exception {
try (JenkinsRule.WebClient wc = j.createWebClient()) {
Expand Down Expand Up @@ -71,39 +91,106 @@ public void doAddCredentialsFromPopupWorksAsExpected() throws Exception {

@Test
@Issue("JENKINS-74964")
public void doAddCredentialsFromPopupForInvalidPEMCertificateKeystore() throws Exception {
public void doAddCredentialsFromPopupForPEMCertificateKeystore() throws Exception {

try (JenkinsRule.WebClient wc = j.createWebClient()) {
HtmlPage htmlPage = wc.goTo("credentials-selection");
HtmlForm form = selectPEMCertificateKeyStore(htmlPage, wc);
form.getTextAreaByName("_.certChain").setTextContent(pemCert);
form.getTextAreaByName("_.privateKey").setTextContent(pemKey);
form.getInputsByName("_.password").forEach(input -> input.setValue(VALID_PASSWORD));
Page submit = HtmlFormUtil.submit(form);
JSONObject responseJson = JSONObject.fromObject(submit.getWebResponse().getContentAsString());
assertThat(responseJson.getString("notificationType"), is("SUCCESS"));
}
}

HtmlButton addCredentialsButton = htmlPage.querySelector(".credentials-add-menu");
addCredentialsButton.fireEvent("mouseenter");
addCredentialsButton.click();
@Test
@Issue("JENKINS-74964")
public void doAddCredentialsFromPopupForPEMCertificateKeystore_missingKeyStore() throws Exception {

HtmlButton jenkinsCredentialsOption = htmlPage.querySelector(".jenkins-dropdown__item");
jenkinsCredentialsOption.click();
try (JenkinsRule.WebClient wc = j.createWebClient()) {
HtmlPage htmlPage = wc.goTo("credentials-selection");
HtmlForm form = selectPEMCertificateKeyStore(htmlPage, wc);
Page submit = HtmlFormUtil.submit(form);
JSONObject responseJson = JSONObject.fromObject(submit.getWebResponse().getContentAsString());
assertThat(responseJson.getString("notificationType"), is("ERROR"));
}
}

wc.waitForBackgroundJavaScript(4000);
HtmlForm form = htmlPage.querySelector("#credentials-dialog-form");
String certificateDisplayName = j.jenkins.getDescriptor(CertificateCredentialsImpl.class).getDisplayName();
String KeyStoreSourceDisplayName = j.jenkins.getDescriptor(
CertificateCredentialsImpl.PEMEntryKeyStoreSource.class).getDisplayName();
DomNodeList<DomNode> allOptions = htmlPage.getDocumentElement().querySelectorAll(
"select.dropdownList option");
boolean optionFound = selectOption(allOptions, certificateDisplayName);
assertTrue("The Certificate option was not found in the credentials type select", optionFound);
List<HtmlRadioButtonInput> inputs = htmlPage.getDocumentElement().getByXPath(
"//input[contains(@name, 'keyStoreSource') and following-sibling::label[contains(.,'"
+ KeyStoreSourceDisplayName + "')]]");
assertThat("query should return only a singular input", inputs, hasSize(1));
HtmlElementUtil.click(inputs.get(0));
wc.waitForBackgroundJavaScript(4000);
@Test
@Issue("JENKINS-74964")
public void doAddCredentialsFromPopupForInvalidPEMCertificateKeystore_missingCert() throws Exception {

try (JenkinsRule.WebClient wc = j.createWebClient()) {
HtmlPage htmlPage = wc.goTo("credentials-selection");
HtmlForm form = selectPEMCertificateKeyStore(htmlPage, wc);
form.getTextAreaByName("_.certChain").setTextContent(null);
form.getTextAreaByName("_.privateKey").setTextContent(pemKey);
form.getInputsByName("_.password").forEach(input -> input.setValue(VALID_PASSWORD));
Page submit = HtmlFormUtil.submit(form);
JSONObject responseJson = JSONObject.fromObject(submit.getWebResponse().getContentAsString());
assertThat(responseJson.getString("notificationType"), is("ERROR"));
}
}

@Test
@Issue("JENKINS-74964")
public void doAddCredentialsFromPopupForInvalidPEMCertificateKeystore_missingPassword() throws Exception {

try (JenkinsRule.WebClient wc = j.createWebClient()) {
HtmlPage htmlPage = wc.goTo("credentials-selection");
HtmlForm form = selectPEMCertificateKeyStore(htmlPage, wc);
form.getTextAreaByName("_.certChain").setTextContent(pemCert);
form.getTextAreaByName("_.privateKey").setTextContent(pemKey);
Page submit = HtmlFormUtil.submit(form);
JSONObject responseJson = JSONObject.fromObject(submit.getWebResponse().getContentAsString());
assertThat(responseJson.getString("notificationType"), is("ERROR"));
}
}

@Test
@Issue("JENKINS-74964")
public void doAddCredentialsFromPopupForInvalidPEMCertificateKeystore_invalidPassword() throws Exception {

try (JenkinsRule.WebClient wc = j.createWebClient()) {
HtmlPage htmlPage = wc.goTo("credentials-selection");
HtmlForm form = selectPEMCertificateKeyStore(htmlPage, wc);
form.getTextAreaByName("_.certChain").setTextContent(pemCert);
form.getTextAreaByName("_.privateKey").setTextContent(pemKey);
form.getInputsByName("_.password").forEach(input -> input.setValue(INVALID_PASSWORD));
Page submit = HtmlFormUtil.submit(form);
JSONObject responseJson = JSONObject.fromObject(submit.getWebResponse().getContentAsString());
assertThat(responseJson.getString("notificationType"), is("ERROR"));
}
}

private HtmlForm selectPEMCertificateKeyStore(HtmlPage htmlPage, JenkinsRule.WebClient wc) throws IOException {
HtmlButton addCredentialsButton = htmlPage.querySelector(".credentials-add-menu");
addCredentialsButton.fireEvent("mouseenter");
addCredentialsButton.click();

HtmlButton jenkinsCredentialsOption = htmlPage.querySelector(".jenkins-dropdown__item");
jenkinsCredentialsOption.click();

wc.waitForBackgroundJavaScript(4000);
HtmlForm form = htmlPage.querySelector("#credentials-dialog-form");
String certificateDisplayName = j.jenkins.getDescriptor(CertificateCredentialsImpl.class).getDisplayName();
String KeyStoreSourceDisplayName = j.jenkins.getDescriptor(
CertificateCredentialsImpl.PEMEntryKeyStoreSource.class).getDisplayName();
DomNodeList<DomNode> allOptions = htmlPage.getDocumentElement().querySelectorAll(
"select.dropdownList option");
boolean optionFound = selectOption(allOptions, certificateDisplayName);
assertTrue("The Certificate option was not found in the credentials type select", optionFound);
List<HtmlRadioButtonInput> inputs = htmlPage.getDocumentElement().getByXPath(
"//input[contains(@name, 'keyStoreSource') and following-sibling::label[contains(.,'"
+ KeyStoreSourceDisplayName + "')]]");
assertThat("query should return only a singular input", inputs, hasSize(1));
HtmlElementUtil.click(inputs.get(0));
wc.waitForBackgroundJavaScript(4000);
return form;
}

private static boolean selectOption(DomNodeList<DomNode> allOptions, String optionName) {
return allOptions.stream().anyMatch(domNode -> {
if (domNode instanceof HtmlOption option) {
Expand Down

0 comments on commit fe5d266

Please sign in to comment.