diff --git a/README.md b/README.md index 8fb7cea..ada9b9f 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,21 @@ A java integration library for AeroGear Digger ## Usage +Build a default client: +``` + DiggerClient client = DiggerClient.createDefaultWithAuth("https://digger.com", "admin", "password"); +``` + +Build a customized client: +``` + DiggerClient client = DiggerClient.builder() + .jobService(new JobService()) + .triggerBuildService(new BuildService(10000, 100)) + .artifactsService(artifactsService) + .withAuth("https://digger.com", "admin", "password") + .build(); +``` + Create job: ``` diff --git a/pom.xml b/pom.xml index 0d09fa4..e30ff9d 100644 --- a/pom.xml +++ b/pom.xml @@ -4,11 +4,21 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - groupId + org.jboss.aerogear jenkins-client 1.0.0 jar + + 4.11 + 1.9.5 + 0.3.7-SNAPSHOT + 5.65 + 1.7.21 + 1.7.21 + 3.6.1 + + Apache License, Version 2.0 @@ -22,42 +32,41 @@ com.offbytwo.jenkins jenkins-client - 0.3.7-SNAPSHOT + ${jenkins.client.version} org.jtwig jtwig-core - 5.65 + ${jtwig.templates.version} org.slf4j slf4j-api - 1.7.21 + ${slf4j.api.version} org.slf4j slf4j-log4j12 - 1.7.21 + ${slf4j-log4j12.version} junit junit - 4.12 + ${junit.version} test - org.mockito mockito-core - 1.10.19 + ${mockito-core.version} test org.assertj assertj-core - 3.6.1 + ${assertj-core.version} test diff --git a/src/main/java/com/redhat/digkins/DiggerClient.java b/src/main/java/com/redhat/digkins/DiggerClient.java index 5181816..abaf8ba 100644 --- a/src/main/java/com/redhat/digkins/DiggerClient.java +++ b/src/main/java/com/redhat/digkins/DiggerClient.java @@ -2,14 +2,17 @@ import com.offbytwo.jenkins.JenkinsServer; import com.redhat.digkins.model.BuildStatus; -import com.redhat.digkins.services.CreateJobService; +import com.redhat.digkins.services.ArtifactsService; +import com.redhat.digkins.services.JobService; import com.redhat.digkins.services.TriggerBuildService; import com.redhat.digkins.util.DiggerClientException; import com.redhat.digkins.util.JenkinsAuth; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; @@ -22,14 +25,19 @@ public class DiggerClient { public static final long DEFAULT_BUILD_TIMEOUT = 60 * 1000; - private final JenkinsServer jenkins; + private JenkinsServer jenkinsServer; - public DiggerClient(JenkinsAuth auth) throws URISyntaxException { - this.jenkins = new JenkinsServer(new URI(auth.getUrl()), auth.getUser(), auth.getPassword()); + private JobService jobService; + private TriggerBuildService triggerBuildService; + private ArtifactsService artifactsService; + + private DiggerClient() { } /** - * Create client using provided url and credentials + * Create a client with defaults using provided url and credentials. + *

+ * This client will use the defaults for the services. This is perfectly fine for majorith of the cases. * * @param url Jenkins url * @param user Jenkins user @@ -37,15 +45,62 @@ public DiggerClient(JenkinsAuth auth) throws URISyntaxException { * @return client instance * @throws DiggerClientException if something goes wrong */ - public static DiggerClient from(String url, String user, String password) throws DiggerClientException { - try { - JenkinsAuth jenkinsAuth = new JenkinsAuth(url, user, password); - return new DiggerClient(jenkinsAuth); - } catch (URISyntaxException e) { - throw new DiggerClientException("Invalid jenkins url format."); + public static DiggerClient createDefaultWithAuth(String url, String user, String password) throws DiggerClientException { + TriggerBuildService triggerBuildService = new TriggerBuildService(TriggerBuildService.DEFAULT_FIRST_CHECK_DELAY, TriggerBuildService.DEFAULT_POLL_PERIOD); + JobService jobService = new JobService(); + ArtifactsService artifactsService = new ArtifactsService(); + return DiggerClient.builder() + .createJobService(jobService) + .triggerBuildService(triggerBuildService) + .artifactsService(artifactsService) + .withAuth(url, user, password) + .build(); + } + + public static DiggerClientBuilder builder() { + return new DiggerClientBuilder(); + } + public static class DiggerClientBuilder { + private JenkinsAuth auth; + private JobService jobService; + private TriggerBuildService triggerBuildService; + private ArtifactsService artifactsService; + + public DiggerClientBuilder withAuth(String url, String user, String password) { + this.auth = new JenkinsAuth(url, user, password); + return this; + } + + public DiggerClientBuilder createJobService(JobService jobService) { + this.jobService = jobService; + return this; + } + + public DiggerClientBuilder triggerBuildService(TriggerBuildService triggerBuildService) { + this.triggerBuildService = triggerBuildService; + return this; + } + + public DiggerClientBuilder artifactsService(ArtifactsService artifactsService) { + this.artifactsService = artifactsService; + return this; + } + + public DiggerClient build() throws DiggerClientException { + final DiggerClient client = new DiggerClient(); + try { + client.jenkinsServer = new JenkinsServer(new URI(auth.getUrl()), auth.getUser(), auth.getPassword()); + client.jobService = this.jobService; + client.triggerBuildService = this.triggerBuildService; + client.artifactsService = this.artifactsService; + return client; + } catch (URISyntaxException e) { + throw new DiggerClientException("Invalid jenkins url format."); + } } } + /** * Create new Digger job on Jenkins platform * @@ -55,9 +110,8 @@ public static DiggerClient from(String url, String user, String password) throws * @throws DiggerClientException if something goes wrong */ public void createJob(String name, String gitRepo, String gitBranch) throws DiggerClientException { - CreateJobService service = new CreateJobService(this.jenkins); try { - service.create(name, gitRepo, gitBranch); + jobService.create(this.jenkinsServer, name, gitRepo, gitBranch); } catch (Throwable e) { throw new DiggerClientException(e); } @@ -72,7 +126,7 @@ public void createJob(String name, String gitRepo, String gitBranch) throws Digg * This method will block until there is a build number, or the given timeout period is passed. If the build is still in the queue * after the given timeout period, a {@code BuildStatus} is returned with state {@link BuildStatus.State#TIMED_OUT}. *

- * Please note that timeout period is never meant to be very precise. It has the resolution of {@link TriggerBuildService#POLL_PERIOD} because + * Please note that timeout period is never meant to be very precise. It has the resolution of {@link TriggerBuildService#DEFAULT_POLL_PERIOD} because * timeout is checked before every pull. *

* Similarly, {@link BuildStatus.State#CANCELLED_IN_QUEUE} is returned if the build is cancelled on Jenkins side and @@ -80,14 +134,13 @@ public void createJob(String name, String gitRepo, String gitBranch) throws Digg * * @param jobName name of the job to trigger the build * @param timeout how many milliseconds should this call block before returning {@link BuildStatus.State#TIMED_OUT}. - * Should be larger than {@link TriggerBuildService#FIRST_CHECK_DELAY} + * Should be larger than {@link TriggerBuildService#DEFAULT_FIRST_CHECK_DELAY} * @return the build status * @throws DiggerClientException if connection problems occur during connecting to Jenkins */ public BuildStatus build(String jobName, long timeout) throws DiggerClientException { - final TriggerBuildService triggerBuildService = new TriggerBuildService(jenkins); try { - return triggerBuildService.build(jobName, timeout); + return triggerBuildService.build(this.jenkinsServer, jobName, timeout); } catch (IOException e) { LOG.debug("Exception while connecting to Jenkins", e); throw new DiggerClientException(e); @@ -114,4 +167,32 @@ public BuildStatus build(String jobName) throws DiggerClientException { return this.build(jobName, DEFAULT_BUILD_TIMEOUT); } + /** + * Fetch artifacts urls for specific job and build number + * + * @param jobName name of the job + * @param buildNumber job build number + * @param artifactName - name of the artifact to fetch - can be regexp + * @return InputStream with file contents + * @throws DiggerClientException - when problem with fetching artifacts from jenkins + */ + public InputStream fetchArtifact(String jobName, int buildNumber, String artifactName) throws DiggerClientException { + return artifactsService.streamArtifact(jenkinsServer,jobName, buildNumber, artifactName); + } + + /** + * Save artifact for specified location for specific job, build number and artifact name. + * If name would be an regular expression method would return stream for the first match. + * + * @param jobName name of the job + * @param buildNumber job build number + * @param artifactName name of the artifact to fetch - can be regexp for example *.apk + * @param outputFile file (location) used to save artifact + * + * @throws DiggerClientException when problem with fetching artifacts from jenkins + * @throws IOException when one of the files cannot be saved + */ + public void saveArtifact(String jobName, int buildNumber, String artifactName, File outputFile) throws DiggerClientException, IOException { + artifactsService.saveArtifact(jenkinsServer,jobName, buildNumber, artifactName,outputFile); + } } diff --git a/src/main/java/com/redhat/digkins/Main.java b/src/main/java/com/redhat/digkins/Main.java new file mode 100644 index 0000000..7800df4 --- /dev/null +++ b/src/main/java/com/redhat/digkins/Main.java @@ -0,0 +1,36 @@ +package com.redhat.digkins; + +import com.redhat.digkins.services.JobService; +import com.redhat.digkins.services.TriggerBuildService; +import com.redhat.digkins.util.DiggerClientException; +import org.apache.commons.io.IOUtils; + +import java.io.*; + +/** + */ +public class Main { + + public static void main(String[] args) throws DiggerClientException, IOException { + DiggerClient client = DiggerClient.builder() + .createJobService(new JobService()) + .triggerBuildService(new TriggerBuildService(10000, 100)) + .withAuth("https://jenkins-digger2.osm3.feedhenry.net", "admin", "Vu8ysYH5f2dJiLgL") + .build(); + //client.createJob("wtr-java-tests2", "https://github.com/wtrocki/helloworld-android-gradle", "master"); + //client.build("wtr-java-tests2"); + InputStream inputStream = client.fetchArtifact("wtr-java-tests2", 1, "app-debug.apk"); + if(inputStream != null){ + File targetFile = new File("artifact.tmp"); + OutputStream outStream = new FileOutputStream(targetFile); + + byte[] buffer = new byte[8 * 1024]; + int bytesRead; + while ((bytesRead = inputStream.read(buffer)) != -1) { + outStream.write(buffer, 0, bytesRead); + } + IOUtils.closeQuietly(inputStream); + IOUtils.closeQuietly(outStream); + } + } +} diff --git a/src/main/java/com/redhat/digkins/services/ArtifactsService.java b/src/main/java/com/redhat/digkins/services/ArtifactsService.java new file mode 100644 index 0000000..68efca8 --- /dev/null +++ b/src/main/java/com/redhat/digkins/services/ArtifactsService.java @@ -0,0 +1,94 @@ +package com.redhat.digkins.services; + +import com.offbytwo.jenkins.JenkinsServer; +import com.offbytwo.jenkins.model.Artifact; +import com.offbytwo.jenkins.model.Build; +import com.offbytwo.jenkins.model.BuildWithDetails; +import com.offbytwo.jenkins.model.JobWithDetails; +import com.redhat.digkins.util.DiggerClientException; +import org.apache.commons.io.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.*; +import java.net.URISyntaxException; +import java.util.List; + +/** + * Service used to retrieve artifacts + */ +public class ArtifactsService { + + /** + */ + public ArtifactsService() { + } + + private static final Logger LOG = LoggerFactory.getLogger(ArtifactsService.class); + private static int DEFAULT_BUFFER = 8 * 1024; + + /** + * Save artifact for specified location for specific job, build number and artifact name. + * If name would be an regular expression method would return stream for the first match. + * + * @param jobName name of the job + * @param buildNumber job build number + * @param artifactName name of the artifact to fetch - can be regexp for example *.apk + * @param outputFile file (location) used to save artifact + * @throws DiggerClientException when problem with fetching artifacts from jenkins + * @throws IOException when one of the files cannot be saved + */ + public void saveArtifact(JenkinsServer jenkins, String jobName, int buildNumber, String artifactName, File outputFile) throws DiggerClientException, IOException { + InputStream inputStream = streamArtifact(jenkins, jobName, buildNumber, artifactName); + if (inputStream != null) { + OutputStream outStream = new FileOutputStream(outputFile); + byte[] buffer = new byte[DEFAULT_BUFFER]; + int bytesRead; + while ((bytesRead = inputStream.read(buffer)) != -1) { + outStream.write(buffer, 0, bytesRead); + } + IOUtils.closeQuietly(inputStream); + IOUtils.closeQuietly(outStream); + } else { + throw new DiggerClientException("Cannot fetch artifacts from jenkins"); + } + } + + /** + * Get artifact inputstream for specific job, build number and artifact name. + * If name would be an regular expression method would return stream for the first match. + * + * @param jobName name of the job + * @param buildNumber job build number + * @param artifactName name of the artifact to fetch - can be regexp for example *.apk + * @return InputStream with file contents that can be saved or piped to socket + * @throws DiggerClientException when problem with fetching artifacts from jenkins + */ + public InputStream streamArtifact(JenkinsServer jenkins, String jobName, int buildNumber, String artifactName) throws DiggerClientException { + try { + JobWithDetails job = jenkins.getJob(jobName); + if (job == null) { + LOG.error("Cannot fetch job from jenkins {0}", jobName); + throw new DiggerClientException("Cannot fetch job from jenkins"); + } + Build build = job.getBuildByNumber(buildNumber); + BuildWithDetails buildWithDetails = build.details(); + List artifacts = buildWithDetails.getArtifacts(); + for (Artifact artifact : artifacts) { + if (artifact.getFileName().matches(artifactName)) { + LOG.debug("Streaming artifact {0}", artifactName); + return buildWithDetails.downloadArtifact(artifact); + } + } + } catch (URISyntaxException e) { + LOG.error("Invalid job name {0}", jobName, e); + throw new DiggerClientException(e); + } catch (IOException e) { + LOG.error("Problem when fetching artifacts for {0} {1} {2}", jobName, buildNumber, artifactName, e); + throw new DiggerClientException(e); + } + LOG.debug("Cannot find build for ", jobName, buildNumber, artifactName); + return null; + } + +} diff --git a/src/main/java/com/redhat/digkins/services/CreateJobService.java b/src/main/java/com/redhat/digkins/services/CreateJobService.java deleted file mode 100644 index 6d37a48..0000000 --- a/src/main/java/com/redhat/digkins/services/CreateJobService.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.redhat.digkins.services; - -import com.offbytwo.jenkins.JenkinsServer; -import org.jtwig.JtwigModel; -import org.jtwig.JtwigTemplate; - -import java.io.IOException; - -/** - * Create digger job on jenkins platform - */ -public class CreateJobService { - - private final static String GIT_REPO_URL = "GIT_REPO_URL"; - private final static String GIT_REPO_BRANCH = "GIT_REPO_BRANCH"; - - private JenkinsServer jenkins; - - /** - * @param jenkins jenkins api instance - */ - public CreateJobService(JenkinsServer jenkins) { - this.jenkins = jenkins; - } - - /** - * Create new digger job on jenkins platform - * - * @param name job name that can be used later to reference job - * @param gitRepo git repository url (full git repository url. e.g git@github.com:digger/helloworld.git - * @param gitBranch git repository branch (default branch used to checkout source code) - */ - public void create(String name, String gitRepo, String gitBranch) throws IOException { - JtwigTemplate template = JtwigTemplate.classpathTemplate("templates/job.xml"); - JtwigModel model = JtwigModel.newModel().with(GIT_REPO_URL, gitRepo).with(GIT_REPO_BRANCH, gitBranch); - jenkins.createJob(name, template.render(model)); - } - -} diff --git a/src/main/java/com/redhat/digkins/services/JobService.java b/src/main/java/com/redhat/digkins/services/JobService.java new file mode 100644 index 0000000..521fc1d --- /dev/null +++ b/src/main/java/com/redhat/digkins/services/JobService.java @@ -0,0 +1,31 @@ +package com.redhat.digkins.services; + +import com.offbytwo.jenkins.JenkinsServer; +import org.jtwig.JtwigModel; +import org.jtwig.JtwigTemplate; + +import java.io.IOException; + +/** + * Create digger job on jenkins platform + */ +public class JobService { + + private final static String GIT_REPO_URL = "GIT_REPO_URL"; + private final static String GIT_REPO_BRANCH = "GIT_REPO_BRANCH"; + private static final String JOB_TEMPLATE_PATH = "templates/job.xml"; + + /** + * Create new digger job on jenkins platform + * + * @param jenkinsServer Jenkins server client + * @param name job name that can be used later to reference job + * @param gitRepo git repository url (full git repository url. e.g git@github.com:digger/helloworld.git + * @param gitBranch git repository branch (default branch used to checkout source code) + */ + public void create(JenkinsServer jenkinsServer, String name, String gitRepo, String gitBranch) throws IOException { + JtwigTemplate template = JtwigTemplate.classpathTemplate(JOB_TEMPLATE_PATH); + JtwigModel model = JtwigModel.newModel().with(GIT_REPO_URL, gitRepo).with(GIT_REPO_BRANCH, gitBranch); + jenkinsServer.createJob(name, template.render(model)); + } +} diff --git a/src/main/java/com/redhat/digkins/services/TriggerBuildService.java b/src/main/java/com/redhat/digkins/services/TriggerBuildService.java index 3857dc2..68864f9 100644 --- a/src/main/java/com/redhat/digkins/services/TriggerBuildService.java +++ b/src/main/java/com/redhat/digkins/services/TriggerBuildService.java @@ -19,36 +19,40 @@ public class TriggerBuildService { private static final Logger LOG = LoggerFactory.getLogger(TriggerBuildService.class); /** - * How long should we wait before we start checking the queue item status. + * Default value of {@link #firstCheckDelay} */ - public static final long FIRST_CHECK_DELAY = 5 * 1000L; + public static final long DEFAULT_FIRST_CHECK_DELAY = 5 * 1000L; /** - * How long should we wait before checking the queue item status for next time. + * Default value of {@link #pollPeriod} */ - public static final long POLL_PERIOD = 2 * 1000L; + public static final long DEFAULT_POLL_PERIOD = 2 * 1000L; - private JenkinsServer jenkinsServer; + private long firstCheckDelay; + private long pollPeriod; /** - * @param jenkinsServer jenkins api instance + * @param firstCheckDelay how long should we wait (in milliseconds) before we start checking the queue item status + * @param pollPeriod how long should we wait (in milliseconds) before checking the queue item status for next time */ - public TriggerBuildService(JenkinsServer jenkinsServer) { - this.jenkinsServer = jenkinsServer; + public TriggerBuildService(long firstCheckDelay, long pollPeriod) { + this.firstCheckDelay = firstCheckDelay; + this.pollPeriod = pollPeriod; } /** * See the documentation in {@link com.redhat.digkins.DiggerClient#build(String, long)} * - * @param jobName name of the job - * @param timeout timeout + * @param jenkinsServer Jenkins server client + * @param jobName name of the job + * @param timeout timeout * @return the build status * @throws IOException if connection problems occur during connecting to Jenkins * @throws InterruptedException if a problem occurs during sleeping between checks * @see com.redhat.digkins.DiggerClient#build(String, long) */ - public BuildStatus build(String jobName, long timeout) throws IOException, InterruptedException { + public BuildStatus build(JenkinsServer jenkinsServer, String jobName, long timeout) throws IOException, InterruptedException { final long whenToTimeout = System.currentTimeMillis() + timeout; LOG.debug("Going to build job with name: {}", jobName); @@ -72,8 +76,8 @@ public BuildStatus build(String jobName, long timeout) throws IOException, Inter // do it until we have an executable. // we would have an executable when the build leaves queue and starts building. - LOG.debug("Going to sleep {} msecs", FIRST_CHECK_DELAY); - Thread.sleep(FIRST_CHECK_DELAY); + LOG.debug("Going to sleep {} msecs", firstCheckDelay); + Thread.sleep(firstCheckDelay); QueueItem queueItem; while (true) { @@ -107,8 +111,8 @@ public BuildStatus build(String jobName, long timeout) throws IOException, Inter } else { LOG.debug("Build did not start executing yet."); if (whenToTimeout > System.currentTimeMillis()) { - LOG.debug("Timeout period has not exceeded yet. Sleeping for {} msecs", POLL_PERIOD); - Thread.sleep(POLL_PERIOD); + LOG.debug("Timeout period has not exceeded yet. Sleeping for {} msecs", pollPeriod); + Thread.sleep(pollPeriod); } else { LOG.debug("Timeout period has exceeded. Returning TIMED_OUT."); return new BuildStatus(BuildStatus.State.TIMED_OUT, -1); diff --git a/src/test/java/com/redhat/digkins/services/ArtifactsServiceTests.java b/src/test/java/com/redhat/digkins/services/ArtifactsServiceTests.java new file mode 100644 index 0000000..59d4fc2 --- /dev/null +++ b/src/test/java/com/redhat/digkins/services/ArtifactsServiceTests.java @@ -0,0 +1,87 @@ +package com.redhat.digkins.services; + +import com.offbytwo.jenkins.JenkinsServer; +import com.offbytwo.jenkins.model.*; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Matchers; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.util.Arrays; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertNull; +import static org.mockito.Matchers.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class ArtifactsServiceTests { + + @Mock + private JenkinsServer server; + private ArtifactsService artifactsService; + + @Before + public void beforeTests() { + artifactsService = new ArtifactsService(); + } + + @Test + public void shouldFetchArtifactsWithNoResults() throws Exception { + BuildWithDetails build = mock(BuildWithDetails.class); + JobWithDetails job = mock(JobWithDetails.class); + when(server.getJob(anyString())).thenReturn(job); + when(job.getBuildByNumber(anyInt())).thenReturn(build); + when(build.details()).thenReturn(build); + InputStream artifact = artifactsService.streamArtifact(server, "artifact", 1, "test"); + + assertNull(artifact); + } + + @Test + public void shouldFetchArtifactsWithResults() throws Exception { + Artifact artifact = mock(Artifact.class); + JobWithDetails job = mock(JobWithDetails.class); + BuildWithDetails build = mock(BuildWithDetails.class); + FileInputStream fs = mock(FileInputStream.class); + when(server.getJob(anyString())).thenReturn(job); + when(job.getBuildByNumber(anyInt())).thenReturn(build); + when(build.details()).thenReturn(build); + when(build.getArtifacts()).thenReturn(Arrays.asList(artifact)); + when(build.downloadArtifact(artifact)).thenReturn(fs); + String artifactName = "test"; + when(artifact.getFileName()).thenReturn(artifactName); + InputStream artifactStream = artifactsService.streamArtifact(server, "artifact", 1, artifactName); + + assertThat(artifactStream).isNotNull(); + } + + + @Test + public void shouldSaveFileArtifactWithResults() throws Exception { + Artifact artifact = mock(Artifact.class); + FileInputStream fs = mock(FileInputStream.class); + JobWithDetails job = mock(JobWithDetails.class); + BuildWithDetails build = mock(BuildWithDetails.class); + String artifactName = "test"; + when(server.getJob(anyString())).thenReturn(job); + when(job.getBuildByNumber(anyInt())).thenReturn(build); + when(build.details()).thenReturn(build); + when(build.getArtifacts()).thenReturn(Arrays.asList(artifact)); + when(artifact.getFileName()).thenReturn(artifactName); + when(build.downloadArtifact(artifact)).thenReturn(fs); + when(fs.read(Matchers.anyObject())).thenReturn(-1); + when(build.details()).thenReturn(build); + File outputFile = new File("test.out"); + artifactsService.saveArtifact(server, "artifact", 1, artifactName, outputFile); + + assertThat(outputFile.exists()).isTrue(); + outputFile.delete(); + } +} diff --git a/src/test/java/com/redhat/digkins/services/JobServiceTests.java b/src/test/java/com/redhat/digkins/services/JobServiceTests.java new file mode 100644 index 0000000..96bc0cc --- /dev/null +++ b/src/test/java/com/redhat/digkins/services/JobServiceTests.java @@ -0,0 +1,39 @@ +package com.redhat.digkins.services; + +import com.offbytwo.jenkins.JenkinsServer; +import com.offbytwo.jenkins.model.BuildWithDetails; +import com.offbytwo.jenkins.model.JobWithDetails; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + + +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.*; + +@RunWith(MockitoJUnitRunner.class) +public class JobServiceTests { + + @Mock + private JenkinsServer server; + private JobService jobService; + + @Before + public void beforeTests() { + jobService = new JobService(); + } + + @Test + public void shouldCreateJob() throws Exception { + JobWithDetails job = mock(JobWithDetails.class); + BuildWithDetails build = mock(BuildWithDetails.class); + when(job.getBuildByNumber(anyInt())).thenReturn(build); + when(build.details()).thenReturn(build); + jobService.create(server, "name", "repo", "branch"); + verify(server, times(1)).createJob(anyString(), anyString()); + } + +} diff --git a/src/test/java/com/redhat/digkins/services/TriggerBuildServiceTest.java b/src/test/java/com/redhat/digkins/services/TriggerBuildServiceTest.java index 52fd7f6..247bdad 100644 --- a/src/test/java/com/redhat/digkins/services/TriggerBuildServiceTest.java +++ b/src/test/java/com/redhat/digkins/services/TriggerBuildServiceTest.java @@ -11,11 +11,10 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Mockito; - -import static org.assertj.core.api.Assertions.*; - import org.mockito.runners.MockitoJUnitRunner; +import static org.assertj.core.api.Assertions.assertThat; + @RunWith(MockitoJUnitRunner.class) public class TriggerBuildServiceTest { @@ -32,27 +31,27 @@ public class TriggerBuildServiceTest { @Before public void setUp() throws Exception { - service = new TriggerBuildService(jenkinsServer); + service = new TriggerBuildService(300, 50); // wait for 300 msecs for initial build, check every 50 msecs Mockito.when(jenkinsServer.getJob("TEST")).thenReturn(mockJob); } @Test(expected = IllegalArgumentException.class) public void shouldThrowExceptionIfJobCannotBeFound() throws Exception { - service.build("UNKNOWN", 10000); + service.build(jenkinsServer, "UNKNOWN", 10000); } @Test(expected = IllegalStateException.class) public void shouldThrowExceptionIfJenkinsDoesNotReturnQueueReference() throws Exception { Mockito.when(mockJob.build()).thenReturn(null); - service.build("TEST", 10000); + service.build(jenkinsServer, "TEST", 10000); } @Test(expected = IllegalStateException.class) public void shouldThrowExceptionIfQueueItemIsNullForReference() throws Exception { Mockito.when(mockJob.build()).thenReturn(queueReference); Mockito.when(jenkinsServer.getQueueItem(queueReference)).thenReturn(null); - service.build("TEST", 10000); + service.build(jenkinsServer, "TEST", 10000); } @Test @@ -63,7 +62,7 @@ public void shouldReturnCancelledStatus() throws Exception { Mockito.when(mockJob.build()).thenReturn(queueReference); Mockito.when(jenkinsServer.getQueueItem(queueReference)).thenReturn(queueItem); - final BuildStatus buildStatus = service.build("TEST", 10000); + final BuildStatus buildStatus = service.build(jenkinsServer, "TEST", 10000); assertThat(buildStatus).isNotNull(); assertThat(buildStatus.getState()).isEqualTo(BuildStatus.State.CANCELLED_IN_QUEUE); } @@ -76,7 +75,7 @@ public void shouldReturnStuckStatus() throws Exception { Mockito.when(mockJob.build()).thenReturn(queueReference); Mockito.when(jenkinsServer.getQueueItem(queueReference)).thenReturn(queueItem); - final BuildStatus buildStatus = service.build("TEST", 10000); + final BuildStatus buildStatus = service.build(jenkinsServer, "TEST", 10000); assertThat(buildStatus).isNotNull(); assertThat(buildStatus.getState()).isEqualTo(BuildStatus.State.STUCK_IN_QUEUE); } @@ -90,7 +89,7 @@ public void shouldReturnBuildNumber() throws Exception { Mockito.when(mockJob.build()).thenReturn(queueReference); Mockito.when(jenkinsServer.getQueueItem(queueReference)).thenReturn(queueItem); - final BuildStatus buildStatus = service.build("TEST", 10000); + final BuildStatus buildStatus = service.build(jenkinsServer, "TEST", 10000); assertThat(buildStatus).isNotNull(); assertThat(buildStatus.getState()).isEqualTo(BuildStatus.State.BUILDING); @@ -108,7 +107,7 @@ public void shouldReturnBuildNumber_whenDidNotStartExecutingImmediately() throws Mockito.when(mockJob.build()).thenReturn(queueReference); // return `not-building` for the first 2 checks, then return `building` Mockito.when(jenkinsServer.getQueueItem(queueReference)).thenReturn(queueItemNotBuildingYet, queueItemNotBuildingYet, queueItemBuilding); - final BuildStatus buildStatus = service.build("TEST", 20000L); + final BuildStatus buildStatus = service.build(jenkinsServer, "TEST", 10000L); assertThat(buildStatus).isNotNull(); assertThat(buildStatus.getState()).isEqualTo(BuildStatus.State.BUILDING); @@ -123,7 +122,7 @@ public void shouldReturnTimeout() throws Exception { Mockito.when(mockJob.build()).thenReturn(queueReference); Mockito.when(jenkinsServer.getQueueItem(queueReference)).thenReturn(queueItemNotBuildingYet); - final BuildStatus buildStatus = service.build("TEST", 10000L); + final BuildStatus buildStatus = service.build(jenkinsServer, "TEST", 500L); assertThat(buildStatus).isNotNull(); assertThat(buildStatus.getState()).isEqualTo(BuildStatus.State.TIMED_OUT);