-
Notifications
You must be signed in to change notification settings - Fork 727
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Provide JUnit5 compatible alternative for RoundTripAbstractTest and R…
…estartableJenkinsRule (#2623) Co-authored-by: strangelookingnerd <[email protected]>
- Loading branch information
1 parent
01e7b59
commit 036b5ae
Showing
5 changed files
with
250 additions
and
51 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
12 changes: 7 additions & 5 deletions
12
integrations/src/test/java/io/jenkins/plugins/casc/RoundTripMailerTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
211 changes: 211 additions & 0 deletions
211
...rness/src/main/java/io/jenkins/plugins/casc/misc/junit/jupiter/AbstractRoundTripTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 { | ||
|
||
@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 + "'"); | ||
} | ||
} |