Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,52 @@

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNotNull;

import javaposse.jobdsl.plugin.GlobalJobDslSecurityConfiguration;
import jenkins.model.GlobalConfiguration;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runners.model.Statement;
import org.junit.jupiter.api.Test;
import org.jvnet.hudson.test.Issue;
import org.jvnet.hudson.test.RestartableJenkinsRule;
import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.junit.jupiter.WithJenkins;

/**
* Created by odavid on 23/12/2017.
*/
public class JobDslGlobalSecurityConfigurationTest {

@Rule
public RestartableJenkinsRule j = new RestartableJenkinsRule();
@WithJenkins
class JobDslGlobalSecurityConfigurationTest {

@Test
public void test_global_dsl_security_can_be_applied() {
j.addStep(validateGlobalDSLSecurity);
void test_global_dsl_security_can_be_applied(@SuppressWarnings("unused") JenkinsRule j) {
GlobalJobDslSecurityConfiguration dslSecurity = getGlobalJobDslSecurityConfiguration();
dslSecurity.setUseScriptSecurity(true);

assertThat("ScriptSecurity", dslSecurity.isUseScriptSecurity(), is(true));
configure();
assertThat("ScriptSecurity", dslSecurity.isUseScriptSecurity(), is(false));
}

@Test
@Issue("#253")
public void test_global_dsl_security_can_be_reapplied_after_restart() {
j.addStep(validateGlobalDSLSecurity);
j.addStep(validateGlobalDSLSecurityAfterRestart, true);
void test_global_dsl_security_can_be_reapplied_after_restart(JenkinsRule j) throws Throwable {
GlobalJobDslSecurityConfiguration dslSecurity = getGlobalJobDslSecurityConfiguration();
dslSecurity.setUseScriptSecurity(true);

assertThat("ScriptSecurity", dslSecurity.isUseScriptSecurity(), is(true));
configure();
assertThat("ScriptSecurity", dslSecurity.isUseScriptSecurity(), is(false));

j.restart();

dslSecurity = getGlobalJobDslSecurityConfiguration();

assertThat("ScriptSecurity", dslSecurity.isUseScriptSecurity(), is(false));
configure();
assertThat("ScriptSecurity", dslSecurity.isUseScriptSecurity(), is(false));
}

private GlobalJobDslSecurityConfiguration getGlobalJobDslSecurityConfiguration() {
final GlobalJobDslSecurityConfiguration dslSecurity =
GlobalJobDslSecurityConfiguration dslSecurity =
GlobalConfiguration.all().get(GlobalJobDslSecurityConfiguration.class);
assertNotNull(dslSecurity);
return dslSecurity;
Expand All @@ -45,34 +59,4 @@ private void configure() throws ConfiguratorException {
.getResource("JobDslGlobalSecurityConfigurationTest.yml")
.toExternalForm());
}

private Statement validateGlobalDSLSecurity = new Statement() {

@Override
public void evaluate() throws Throwable {
final GlobalJobDslSecurityConfiguration dslSecurity = getGlobalJobDslSecurityConfiguration();

dslSecurity.setUseScriptSecurity(true);
assertThat("ScriptSecurity", dslSecurity.isUseScriptSecurity(), is(true));

configure();

assertThat("ScriptSecurity", dslSecurity.isUseScriptSecurity(), is(false));
}
};

private Statement validateGlobalDSLSecurityAfterRestart = new Statement() {

@Override
public void evaluate() throws Throwable {
final GlobalJobDslSecurityConfiguration dslSecurity = getGlobalJobDslSecurityConfiguration();

// step 1 configuration still applies
assertThat("ScriptSecurity", dslSecurity.isUseScriptSecurity(), is(false));

configure();

assertThat("ScriptSecurity", dslSecurity.isUseScriptSecurity(), is(false));
}
};
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
package io.jenkins.plugins.casc;

import static org.junit.Assert.assertEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;

import hudson.tasks.Mailer;
import io.jenkins.plugins.casc.misc.RoundTripAbstractTest;
import io.jenkins.plugins.casc.misc.junit.jupiter.AbstractRoundTripTest;
import jenkins.model.Jenkins;
import org.jvnet.hudson.test.RestartableJenkinsRule;
import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.junit.jupiter.WithJenkins;

public class RoundTripMailerTest extends RoundTripAbstractTest {
@WithJenkins
class RoundTripMailerTest extends AbstractRoundTripTest {
@Override
protected void assertConfiguredAsExpected(RestartableJenkinsRule j, String configContent) {
protected void assertConfiguredAsExpected(JenkinsRule j, String configContent) {
final Jenkins jenkins = Jenkins.get();
final Mailer.DescriptorImpl descriptor = (Mailer.DescriptorImpl) jenkins.getDescriptor(Mailer.class);
assertEquals("4441", descriptor.getSmtpPort());
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>plugin</artifactId>
<version>5.5</version>
<version>5.6</version>
<relativePath />
</parent>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@
* text configured.
*
* @since 1.20
* @deprecated Consider migrating to JUnit5 and use {@link io.jenkins.plugins.casc.misc.junit.jupiter.AbstractRoundTripTest} instead.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is optional, but I'd like to make users aware of the alternative.

*/
@Deprecated
public abstract class RoundTripAbstractTest {
@Rule
public RestartableJenkinsRule r = new RestartableJenkinsRule();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
package io.jenkins.plugins.casc.misc.junit.jupiter;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.htmlunit.HttpMethod.POST;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

import io.jenkins.plugins.casc.ConfigurationAsCode;
import io.jenkins.plugins.casc.ConfiguratorException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.Collections;
import java.util.logging.Level;
import org.apache.commons.io.IOUtils;
import org.htmlunit.WebRequest;
import org.htmlunit.WebResponse;
import org.htmlunit.util.NameValuePair;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.LogRecorder;
import org.jvnet.hudson.test.junit.jupiter.WithJenkins;

/**
* Base test to check a complete test of each plugin configuration.
* <p>
* What it does:
* <ol>
* <li>Configure the instance with the {@link #configResource()} implemented.</li>
* <li>Check it was configured correctly.</li>
* <li>Check the configuration is valid via Web UI.</li>
* <li>Apply the configuration via Web UI.</li>
* <li>Write the configuration to $JENKINS_HOME/jenkins.yaml.</li>
* <li>Restart Jenkins.</li>
* <li>Check the {@link #stringInLogExpected()} is set during the restart.</li>
* <li>Check it is still configured correctly after the restart</li>
* </ol>
* <p>
* All the plugin author needs to do is override the methods providing:
* <ol>
* <li>The resource with the yaml configuration of the plugin in case they use their own name for the file.</li>
* <li>A way to validate the configuration is established.</li>
* <li>A string that should be present in the logs (casc logger) that guarantees the config is loaded. Usually a weird text configured.</li>
* </ol>
* <p>
* This is the JUnit5 equivalent of {@link io.jenkins.plugins.casc.misc.RoundTripAbstractTest}
*
* @see io.jenkins.plugins.casc.misc.RoundTripAbstractTest
*/
@WithJenkins
public abstract class AbstractRoundTripTest {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used a slightly different name besides a different package to reduce the risk of mix-ups. Not sure if this is the best way, so feedback is welcome.


@TempDir
public Path tempFolder;

/**
* A method to assert if the configuration was correctly loaded. The Jenkins rule and the
* content of the config supposedly loaded are passed.
*
* @param j a JenkinsRule instance.
* @param configContent expected configuration.
*/
protected abstract void assertConfiguredAsExpected(JenkinsRule j, String configContent);

/**
* Return the resource path (yaml file) to be loaded. i.e: If the resource is in the same
* package of the implementor class, then: my-config.yaml
*
* @return the resource name and path.
*/
protected String configResource() {
return "configuration-as-code.yaml";
}

/**
* Return the string that should be in the logs of the JCasC logger to verify it's configured
* after a restart. This string should be unique to avoid interpreting that it was configured
* successfully, but it wasn't.
*
* @return the unique string to be in the logs to certify the configuration was done
* successfully.
*/
protected abstract String stringInLogExpected();

/**
* 1. Configure the instance with the {@link #configResource()} implemented. 2. Check it was
* configured correctly. 3. Check the configuration is valid via Web UI. 4. Apply the
* configuration via Web UI. 5. Write the configuration to $JENKINS_HOME/jenkins.yaml. 6.
* Restart Jenkins. 7. Check the {@link #stringInLogExpected()} is set during the restart.
*
* @throws IOException If an exception is thrown managing resources or files.
*/
@Test
public void roundTripTest(JenkinsRule r) throws Throwable {
String resourcePath = configResource();
String resourceContent = getResourceContent(resourcePath);

assertNotNull(resourcePath);
assertNotNull(resourceContent);

// Configure and validate
configureWithResource(resourcePath);
assertConfiguredAsExpected(r, resourceContent);

// Check config is valid via Web UI
String jenkinsConf = getResourceContent(resourcePath);
assertConfigViaWebUI(r, jenkinsConf);

// Apply configuration via Web UI
applyConfigViaWebUI(r, jenkinsConf);
assertConfiguredAsExpected(r, resourceContent);

// Configure Jenkins default JCasC file with the config file. It's already established, we check if applied
// looking at the logs.
putConfigInHome(r, jenkinsConf);

// Start recording the logs just before restarting, to avoid capture the previous startup. We're look there
// if the "magic token" is there
try (LogRecorder recorder =
new LogRecorder().record("io.jenkins.plugins.casc", Level.FINER).capture(2048)) {
// Restart the testing instance
r.restart();

// Verify the log shows it's configured
assertLogAsExpected(recorder, stringInLogExpected());
}

// Verify the configuration set at home/jenkins.yaml is loaded
assertConfiguredAsExpected(r, resourceContent);
}

private void configureWithResource(String config) throws ConfiguratorException {
ConfigurationAsCode.get().configure(this.getClass().getResource(config).toExternalForm());
}

private String getResourceContent(String resourcePath) throws IOException {
return IOUtils.toString(getClass().getResourceAsStream(resourcePath), StandardCharsets.UTF_8);
}

private void writeToFile(String text, String path) throws FileNotFoundException {
File file = new File(path);
try (PrintWriter out = new PrintWriter(file)) {
out.print(text);
}
}

private void putConfigInHome(JenkinsRule r, String config) throws Exception {
File configFile = new File(r.getWebAppRoot(), ConfigurationAsCode.DEFAULT_JENKINS_YAML_PATH);

writeToFile(config, configFile.getAbsolutePath());
assertTrue(configFile.exists(), ConfigurationAsCode.DEFAULT_JENKINS_YAML_PATH + " should be created");
}

private void assertConfigViaWebUI(JenkinsRule r, String jenkinsConfig) throws Exception {
// The UI requires the path to the config file
File f = File.createTempFile("junit", null, tempFolder.toFile());
writeToFile(jenkinsConfig, f.getAbsolutePath());

// Call the check url
JenkinsRule.WebClient client = r.createWebClient();
WebRequest request = new WebRequest(client.createCrumbedUrl("configuration-as-code/checkNewSource"), POST);
NameValuePair param = new NameValuePair("newSource", f.toURI().toURL().toExternalForm());
request.setRequestParameters(Collections.singletonList(param));
WebResponse response = client.loadWebResponse(request);
assertEquals(
200,
response.getStatusCode(),
"Failed to POST to " + request.getUrl().toString());
String res = response.getContentAsString();
assertThat(res, containsString("The configuration can be applied"));
}

private void applyConfigViaWebUI(JenkinsRule r, String jenkinsConfig) throws Exception {
// The UI requires the path to the config file
File f = File.createTempFile("junit", null, tempFolder.toFile());
writeToFile(jenkinsConfig, f.getAbsolutePath());

// Call the replace url
JenkinsRule.WebClient client = r.createWebClient();
WebRequest request = new WebRequest(client.createCrumbedUrl("configuration-as-code/replace"), POST);
NameValuePair param = new NameValuePair("_.newSource", f.toURI().toURL().toExternalForm());
request.setRequestParameters(Collections.singletonList(param));
request.setRequestParameters(Collections.singletonList(param));
WebResponse response = client.loadWebResponse(request);
assertEquals(
200,
response.getStatusCode(),
"Failed to POST to " + request.getUrl().toString());
String res = response.getContentAsString();
/* The result page has:
Configuration loaded from :
<ul>
<li>path</li>
</ul>
path is the file used to store the configuration.
*/
assertThat(res, containsString(f.toURI().toURL().toExternalForm()));
}

private void assertLogAsExpected(LogRecorder recorder, String uniqueText) {
assertTrue(
recorder.getMessages().stream().anyMatch(m -> m.contains(uniqueText)),
"The log should have '" + uniqueText + "'");
}
}
Loading