Skip to content

Commit

Permalink
Migrate tests to JUnit5 (#562)
Browse files Browse the repository at this point in the history
* Migrate tests to JUnit5

* Migrate annotations and imports
* Migrate assertions
* Remove public visibility for test classes and methods
* Minor code cleanup

* Update pom.xml

Co-authored-by: Ivan Fernandez Calvo <[email protected]>

---------

Co-authored-by: strangelookingnerd <[email protected]>
Co-authored-by: Ivan Fernandez Calvo <[email protected]>
  • Loading branch information
3 people authored Feb 25, 2025
1 parent a2157c6 commit e2c6128
Show file tree
Hide file tree
Showing 38 changed files with 834 additions and 788 deletions.
3 changes: 2 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,10 @@
<artifactId>test-harness</artifactId>
<scope>test</scope>
</dependency>
<!-- Jupiter/JUnit 5 testcontainers https://java.testcontainers.org/test_framework_integration/junit_5/ -->
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<artifactId>junit-jupiter</artifactId>
<version>1.20.5</version>
<scope>test</scope>
</dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@

import hudson.model.Node;
import hudson.slaves.SlaveComputer;
import io.jenkins.plugins.casc.misc.RoundTripAbstractTest;
import org.jvnet.hudson.test.RestartableJenkinsRule;
import io.jenkins.plugins.casc.misc.junit.jupiter.AbstractRoundTripTest;
import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.junit.jupiter.WithJenkins;

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

@WithJenkins
class SSHLauncherCasCRoundTripTest extends AbstractRoundTripTest {

public class SSHLauncherCasCRoundTripTest extends RoundTripAbstractTest {
@Override
protected void assertConfiguredAsExpected(RestartableJenkinsRule restartableJenkinsRule, String s) {
final Node node = r.j.jenkins.getNode("this-ssh-agent");
protected void assertConfiguredAsExpected(JenkinsRule jenkins, String s) {
final Node node = jenkins.jenkins.getNode("this-ssh-agent");
assertNotNull(node);

SlaveComputer computer = (SlaveComputer) node.toComputer();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,28 @@
import hudson.slaves.SlaveComputer;
import io.jenkins.plugins.casc.misc.ConfiguredWithCode;
import io.jenkins.plugins.casc.misc.JenkinsConfiguredWithCodeRule;
import org.junit.Rule;
import org.junit.Test;
import io.jenkins.plugins.casc.misc.junit.jupiter.WithJenkinsConfiguredWithCode;
import org.junit.jupiter.api.Test;

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

public class SSHLauncherCasCSupportTest {
@Rule
public JenkinsConfiguredWithCodeRule j = new JenkinsConfiguredWithCodeRule();
@WithJenkinsConfiguredWithCode
class SSHLauncherCasCSupportTest {

@Test
@ConfiguredWithCode("SSHCasCConfig.yml")
public void shouldBeAbleToConfigureSSHSlaves() {
validateConfiguration();
void shouldBeAbleToConfigureSSHSlaves(JenkinsConfiguredWithCodeRule j) {
validateConfiguration(j);
}

@Test
@ConfiguredWithCode("SSHCasCConfigLegacy.yml")
public void shouldBeAbleToConfigureLegacySSHSlaves() {
validateConfiguration();
void shouldBeAbleToConfigureLegacySSHSlaves(JenkinsConfiguredWithCodeRule j) {
validateConfiguration(j);
}

private void validateConfiguration() {
private static void validateConfiguration(JenkinsConfiguredWithCodeRule j) {
final Node node = j.jenkins.getNode("this-ssh-agent");
assertNotNull(node);

Expand Down
18 changes: 5 additions & 13 deletions src/test/java/hudson/plugins/sshslaves/SSHLauncherTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.htmlunit.html.HtmlPage;
import org.apache.commons.io.IOUtils;
import org.jenkinsci.test.acceptance.docker.DockerRule;
Expand All @@ -45,17 +43,11 @@
import org.jvnet.hudson.test.JenkinsRule;
import hudson.model.Descriptor;
import hudson.model.Fingerprint;
import hudson.model.JDK;
import hudson.model.Slave;
import hudson.plugins.sshslaves.verifiers.KnownHostsFileKeyVerificationStrategy;
import hudson.plugins.sshslaves.verifiers.NonVerifyingKeyVerificationStrategy;
import hudson.slaves.DumbSlave;
import hudson.slaves.EnvironmentVariablesNodeProperty;
import hudson.slaves.NodeProperty;
import hudson.slaves.SlaveComputer;
import hudson.tools.ToolLocationNodeProperty;
import hudson.util.FormValidation;
import jenkins.model.Jenkins;
import com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey;
import com.cloudbees.plugins.credentials.CredentialsProvider;
import com.cloudbees.plugins.credentials.CredentialsScope;
Expand Down Expand Up @@ -235,23 +227,23 @@ public void workDirTest() {
"javaPath", "prefix", "suffix",
60, 10, 15, new NonVerifyingKeyVerificationStrategy());
//use rootFS
Assert.assertEquals(launcher.getWorkDirParam(rootFS), WORK_DIR_PARAM + rootFS + JAR_CACHE_PARAM + rootFS + JAR_CACHE_DIR);
Assert.assertEquals(WORK_DIR_PARAM + rootFS + JAR_CACHE_PARAM + rootFS + JAR_CACHE_DIR, launcher.getWorkDirParam(rootFS));

launcher = new SSHLauncher("Hostname", 22, "credentialID", "jvmOptions",
"javaPath", "prefix", "suffix" + WORK_DIR_PARAM + anotherWorkDir,
60, 10, 15, new NonVerifyingKeyVerificationStrategy());
//if worDir is in suffix return ""
Assert.assertEquals(launcher.getWorkDirParam(rootFS), "");
Assert.assertEquals("", launcher.getWorkDirParam(rootFS));
//if worDir is in suffix return "", even do you set workDir in configuration
launcher.setWorkDir(anotherWorkDir);
Assert.assertEquals(launcher.getWorkDirParam(rootFS), "");
Assert.assertEquals("", launcher.getWorkDirParam(rootFS));

launcher = new SSHLauncher("Hostname", 22, "credentialID", "jvmOptions",
"javaPath", "prefix", "suffix",
60, 10, 15, new NonVerifyingKeyVerificationStrategy());
//user the workDir set in configuration
launcher.setWorkDir(anotherWorkDir);
Assert.assertEquals(launcher.getWorkDirParam(rootFS), WORK_DIR_PARAM + anotherWorkDir + JAR_CACHE_PARAM + anotherWorkDir + JAR_CACHE_DIR);
Assert.assertEquals(WORK_DIR_PARAM + anotherWorkDir + JAR_CACHE_PARAM + anotherWorkDir + JAR_CACHE_DIR, launcher.getWorkDirParam(rootFS));
}

@Test
Expand Down Expand Up @@ -311,7 +303,7 @@ public void getMd5Hash() {
public void readInputStreamIntoByteArrayAndClose() {

InputStream inputStream = null;
File testFile = null;
File testFile;
try {

testFile = new File("target" + File.separator + "test-classes",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@
import java.util.concurrent.TimeUnit;

import org.apache.commons.io.IOUtils;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.rules.Timeout;
import org.apache.commons.lang.SystemUtils;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
import org.jvnet.hudson.test.JenkinsRule;
import hudson.model.Descriptor;
import hudson.model.Node;
import hudson.model.Slave;
import hudson.model.Descriptor.FormException;
import hudson.plugins.sshslaves.SSHLauncher;
import hudson.plugins.sshslaves.rules.CheckIsDockerAvailable;
import hudson.plugins.sshslaves.rules.CheckIsLinuxOrMac;
import hudson.plugins.sshslaves.verifiers.NonVerifyingKeyVerificationStrategy;
import hudson.slaves.DumbSlave;
import com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey;
Expand All @@ -25,46 +25,76 @@
import com.cloudbees.plugins.credentials.common.StandardUsernameCredentials;
import com.cloudbees.plugins.credentials.domains.Domain;
import com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl;
import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
import org.testcontainers.DockerClientFactory;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.junit.jupiter.Testcontainers;

import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assumptions.assumeTrue;

/**
* Base class to test connections to a remote SSH Agent
*
* @author Kuisathaverat
*/
public class AgentConnectionBase {
public static final String USER = "jenkins";
public static final String PASSWORD = "password";
public static final String AGENT_WORK_DIR = "/home/jenkins";
public static final int SSH_PORT = 22;
public static final String SSH_SSHD_CONFIG = "ssh/sshd_config";
public static final String DOCKERFILE = "Dockerfile";
public static final String SSH_AUTHORIZED_KEYS = "ssh/authorized_keys";
public static final String AGENTS_RESOURCES_PATH = "/hudson/plugins/sshslaves/agents/";

@ClassRule
public static CheckIsLinuxOrMac isLinuxOrMac = new CheckIsLinuxOrMac();

@ClassRule
public static CheckIsDockerAvailable isDockerAvailable = new CheckIsDockerAvailable();

@Rule(order = 10)
public JenkinsRule j = new JenkinsRule();

@Rule(order = -10)
public Timeout globalTimeout = Timeout.builder().withTimeout(10, TimeUnit.MINUTES).withLookingForStuckThread(true).build();

protected AgentConnectionBase() {
j.timeout = 0;
@Timeout(value = 10, unit = TimeUnit.MINUTES)
@WithJenkins
@Testcontainers(disabledWithoutDocker = true)
abstract class AgentConnectionBaseTest {

protected static final String USER = "jenkins";
protected static final String PASSWORD = "password";
protected static final String AGENT_WORK_DIR = "/home/jenkins";
protected static final int SSH_PORT = 22;
protected static final String SSH_SSHD_CONFIG = "ssh/sshd_config";
protected static final String DOCKERFILE = "Dockerfile";
protected static final String SSH_AUTHORIZED_KEYS = "ssh/authorized_keys";
protected static final String AGENTS_RESOURCES_PATH = "/hudson/plugins/sshslaves/agents/";

protected JenkinsRule j;

@BeforeEach
void beforeEach(JenkinsRule j) {
this.j = j;
this.j.timeout = 0;
}

@BeforeAll
static void beforeAll() {
assumeTrue(SystemUtils.IS_OS_MAC || SystemUtils.IS_OS_LINUX);
assumeTrue(DockerClientFactory.instance().isDockerAvailable());
}

protected boolean isSuccessfullyConnected(Node node) throws IOException, InterruptedException {
@Test
void connectionTests() throws IOException, InterruptedException, Descriptor.FormException {
Node node = createPermanentAgent(getAgentName(), getAgentContainer().getHost(), getAgentContainer().getMappedPort(SSH_PORT),
getAgentSshKeyPath(), getAgentSshKeyPassphrase());
waitForAgentConnected(node);
assertTrue(isSuccessfullyConnected(node));
}

protected abstract String getAgentName();

protected abstract GenericContainer<?> getAgentContainer();

protected String getAgentSshKeyPath() {
return null;
}

protected String getAgentSshKeyPassphrase() {
return "";
}

protected static boolean isSuccessfullyConnected(Node node) throws IOException, InterruptedException {
int count = 0;
while (count < 30) {
Thread.sleep(1000);
String log = node.toComputer().getLog();
if (log.contains("Agent successfully connected and online")) {
return true;
}
count++;
}
return false;
}
Expand All @@ -82,25 +112,20 @@ protected void waitForAgentConnected(Node node) throws InterruptedException {
protected Node createPermanentAgent(String name, String host, int sshPort, String keyResourcePath, String passphrase)
throws Descriptor.FormException, IOException {
String credId = "sshCredentialsId";
createSshKeyCredentials(credId, keyResourcePath, passphrase);

if (keyResourcePath != null) {
createSshKeyCredentials(credId, keyResourcePath, passphrase);
} else {
createSshCredentials(credId);
}

final SSHLauncher launcher = new SSHLauncher(host , sshPort, credId);
launcher.setSshHostKeyVerificationStrategy(new NonVerifyingKeyVerificationStrategy());
DumbSlave agent = new DumbSlave(name, AGENT_WORK_DIR, launcher);
j.jenkins.addNode(agent);
return j.jenkins.getNode(agent.getNodeName());
}

protected Node createPermanentAgent(String name, String host, int sshPort)
throws Descriptor.FormException, IOException {
String credId = "sshCredentialsId";
createSshCredentials(credId);
final SSHLauncher launcher = new SSHLauncher(host , sshPort, credId);
launcher.setSshHostKeyVerificationStrategy(new NonVerifyingKeyVerificationStrategy());
DumbSlave agent = new DumbSlave(name, AGENT_WORK_DIR, launcher);
j.jenkins.addNode(agent);
return j.jenkins.getNode(agent.getNodeName());
}

private void createSshKeyCredentials(String id, String keyResourcePath, String passphrase) throws IOException {
String privateKey = IOUtils.toString(getClass().getResourceAsStream(keyResourcePath), StandardCharsets.UTF_8);
BasicSSHUserPrivateKey.DirectEntryPrivateKeySource privateKeySource = new BasicSSHUserPrivateKey.DirectEntryPrivateKeySource(
Expand All @@ -111,7 +136,7 @@ private void createSshKeyCredentials(String id, String keyResourcePath, String p
Collections.singletonList(credentials));
}

private void createSshCredentials(String id) throws IOException, FormException {
private static void createSshCredentials(String id) throws FormException {
StandardUsernameCredentials credentials =
new UsernamePasswordCredentialsImpl(CredentialsScope.SYSTEM, id, "", USER, PASSWORD);
SystemCredentialsProvider.getInstance().getDomainCredentialsMap().put(Domain.global(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,44 +1,48 @@
package hudson.plugins.sshslaves.agents;

import java.io.IOException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import static hudson.plugins.sshslaves.tags.TestTags.AGENT_SSH_TEST;
import static hudson.plugins.sshslaves.tags.TestTags.SSH_KEX_TEST;

import org.junit.jupiter.api.Tag;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.images.builder.ImageFromDockerfile;
import hudson.model.Descriptor;
import hudson.model.Node;
import hudson.plugins.sshslaves.categories.AgentSSHTest;
import hudson.plugins.sshslaves.categories.SSHKexTest;
import static org.junit.Assert.assertTrue;
import org.testcontainers.junit.jupiter.Container;

/**
* Connect to a remote SSH Agent
*
* @author Kuisathaverat
*/
@Category({ AgentSSHTest.class, SSHKexTest.class})
public class AgentCurve25519Sha256ConnectionTest extends AgentConnectionBase {
public static final String SSH_AGENT_NAME = "ssh-agent-curve25519-sha256";
public static final String SSH_KEY_PATH = "ssh/rsa-key";
public static final String SSH_KEY_PUB_PATH = "ssh/rsa-key.pub";

@Rule
public GenericContainer agentContainer = new GenericContainer(
@Tag(AGENT_SSH_TEST)
@Tag(SSH_KEX_TEST)
class AgentCurve25519Sha256ConnectionTest extends AgentConnectionBaseTest {
private static final String SSH_AGENT_NAME = "ssh-agent-curve25519-sha256";
private static final String SSH_KEY_PATH = "ssh/rsa-key";
private static final String SSH_KEY_PUB_PATH = "ssh/rsa-key.pub";

@Container
private static final GenericContainer<?> agentContainer = new GenericContainer<>(
new ImageFromDockerfile(SSH_AGENT_NAME, false)
.withFileFromClasspath(SSH_AUTHORIZED_KEYS, AGENTS_RESOURCES_PATH + "/" + SSH_AGENT_NAME + "/" + SSH_AUTHORIZED_KEYS)
.withFileFromClasspath(SSH_KEY_PATH, AGENTS_RESOURCES_PATH + "/" + SSH_AGENT_NAME + "/" + SSH_KEY_PATH)
.withFileFromClasspath(SSH_KEY_PUB_PATH, AGENTS_RESOURCES_PATH + "/" + SSH_AGENT_NAME + "/" + SSH_KEY_PUB_PATH)
.withFileFromClasspath(SSH_SSHD_CONFIG, AGENTS_RESOURCES_PATH + "/" + SSH_AGENT_NAME + "/" + SSH_SSHD_CONFIG)
.withFileFromClasspath(DOCKERFILE, AGENTS_RESOURCES_PATH + "/" + SSH_AGENT_NAME + "/" + DOCKERFILE))
.withExposedPorts(22);

@Test
public void connectionTests() throws IOException, InterruptedException, Descriptor.FormException {
Node node = createPermanentAgent(SSH_AGENT_NAME, agentContainer.getHost(), agentContainer.getMappedPort(SSH_PORT),
SSH_AGENT_NAME + "/" + SSH_KEY_PATH, "");
waitForAgentConnected(node);
assertTrue(isSuccessfullyConnected(node));
.withExposedPorts(SSH_PORT);

@Override
protected String getAgentName() {
return SSH_AGENT_NAME;
}

@Override
protected GenericContainer<?> getAgentContainer() {
return agentContainer;
}

@Override
protected String getAgentSshKeyPath() {
return SSH_AGENT_NAME + "/" + SSH_KEY_PATH;
}

}
Loading

0 comments on commit e2c6128

Please sign in to comment.