Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add LoggingChecksPublisher and tests for status checks #59

Merged
merged 4 commits into from
Dec 23, 2020
Merged
Show file tree
Hide file tree
Changes from 2 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
@@ -0,0 +1,125 @@
package io.jenkins.plugins.checks.status;

import hudson.model.Job;
import hudson.model.Run;
import io.jenkins.plugins.checks.util.LoggingChecksPublisher;
import io.jenkins.plugins.util.IntegrationTestWithJenkinsPerTest;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;
import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.TestExtension;

import java.io.IOException;

import static org.assertj.core.api.Assertions.assertThat;

/**
* Tests that the {@link BuildStatusChecksPublisher} listens to the status of a {@link Run} and publishes status
* accordingly.
*/
public class BuildStatusChecksPublisherITest extends IntegrationTestWithJenkinsPerTest {
private static final String STATUS_TEMPLATE = "Published Checks (name: %s, status: %s, conclusion %s)%n";

/**
* Provide a {@link io.jenkins.plugins.checks.util.LoggingChecksPublisher} to log details.
*/
@TestExtension
public static final LoggingChecksPublisher.Factory PUBLISHER_FACTORY = new LoggingChecksPublisher.Factory();

/**
* Provide inject an implementation of {@link AbstractStatusChecksProperties} to control the checks.
*/
@TestExtension
public static final ChecksProperties PROPERTIES = new ChecksProperties();

/**
* Tests when the implementation of {@link AbstractStatusChecksProperties} is not applicable,
* a status checks should not be published.
*
* @throws IOException if failed getting log from {@link Run}
*/
@Test
public void shouldNotPublishStatusWhenNotApplicable() throws IOException {
PUBLISHER_FACTORY.setFormatter(details -> String.format(STATUS_TEMPLATE,
details.getName().orElse(StringUtils.EMPTY), details.getStatus(), details.getConclusion()));

PROPERTIES.setApplicable(false);

assertThat(JenkinsRule.getLog(buildSuccessfully(createFreeStyleProject())))
.doesNotContain(String.format(STATUS_TEMPLATE, "Test Status", "IN_PROGRESS", "NONE"))
.doesNotContain(String.format(STATUS_TEMPLATE, "Test Status", "COMPLETED", "SUCCESS"));
}

/**
* Tests when status checks is skipped, a status checks should not be published.
*
* @throws IOException if failed getting log from {@link Run}
*/
@Test
public void shouldNotPublishStatusWhenSkipped() throws IOException {
PUBLISHER_FACTORY.setFormatter(details -> String.format(STATUS_TEMPLATE,
details.getName().orElse(StringUtils.EMPTY), details.getStatus(), details.getConclusion()));

PROPERTIES.setApplicable(true);
PROPERTIES.setSkipped(true);
PROPERTIES.setName("Test Status");

assertThat(JenkinsRule.getLog(buildSuccessfully(createFreeStyleProject())))
.doesNotContain(String.format(STATUS_TEMPLATE, "Test Status", "IN_PROGRESS", "NONE"))
.doesNotContain(String.format(STATUS_TEMPLATE, "Test Status", "COMPLETED", "SUCCESS"));
}

/**
* Tests when an implementation of {@link AbstractStatusChecksProperties} is applicable and not skipped,
* a status checks using the specified name should be published.
*
* @throws IOException if failed getting log from {@link Run}
*/
@Test
public void shouldPublishStatusWithProperties() throws IOException {
PUBLISHER_FACTORY.setFormatter(details -> String.format(STATUS_TEMPLATE,
details.getName().orElse(StringUtils.EMPTY), details.getStatus(), details.getConclusion()));

PROPERTIES.setApplicable(true);
PROPERTIES.setSkipped(false);
PROPERTIES.setName("Test Status");

Run<?, ?> run = buildSuccessfully(createFreeStyleProject());
assertThat(JenkinsRule.getLog(run))
.contains(String.format(STATUS_TEMPLATE, "Test Status", "IN_PROGRESS", "NONE"))
.contains(String.format(STATUS_TEMPLATE, "Test Status", "COMPLETED", "SUCCESS"));
}

static class ChecksProperties extends AbstractStatusChecksProperties {
private boolean applicable;
private boolean skipped;
private String name;

public void setApplicable(final boolean applicable) {
this.applicable = applicable;
}

public void setSkipped(final boolean skipped) {
this.skipped = skipped;
}

public void setName(final String name) {
this.name = name;
}

@Override
public boolean isApplicable(final Job<?, ?> job) {
return applicable;
}

@Override
public String getName(final Job<?, ?> job) {
return name;
}

@Override
public boolean isSkipped(final Job<?, ?> job) {
return skipped;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package io.jenkins.plugins.checks.util;

import hudson.model.Job;
import hudson.model.Run;
import hudson.model.TaskListener;
import io.jenkins.plugins.checks.api.ChecksDetails;
import io.jenkins.plugins.checks.api.ChecksPublisher;
import io.jenkins.plugins.checks.api.ChecksPublisherFactory;

import java.util.Optional;

/**
* Implementation of {@link ChecksPublisher} for use in testing, that logs the checks details in user specified format.
*
* For example:
*
* <pre>
* public class ChecksPublishingTest extends IntegrationTestWithJenkinsPerTest {
*
* &#64;TestExtension
* public static final LoggingChecksPublisher.Factory PUBLISHER_FACTORY = new LoggingChecksPublisher.Factory();
*
* &#64;Test
* public void shouldLogChecks() {
* // ...Run a test job...
* Run<?, ?> run = buildSuccessfully(createFreeStyleProject());
*
* // ...Inspect logs...
* assertThat(JenkinsRule.getLog(run))
* .contains("...")
* .doesNotContain("...");
* }
* }
* </pre>
*
* An example of this can be found in {@link io.jenkins.plugins.checks.status.BuildStatusChecksPublisherITest}
*/
public class LoggingChecksPublisher extends ChecksPublisher {
private Formatter formatter = ChecksDetails::toString;
private TaskListener listener = TaskListener.NULL;

/**
* Logs the {@code details} using the {@link TaskListener}.
*
* @param details
* checks details that will be logged
*/
@Override
public void publish(final ChecksDetails details) {
listener.getLogger().print(formatter.format(details));
}

/**
* Implementation of {@link ChecksPublisherFactory} that returns a {@link LoggingChecksPublisher}.
*/
public static class Factory extends ChecksPublisherFactory {
private final LoggingChecksPublisher publisher = new LoggingChecksPublisher();

public void setFormatter(final Formatter formatter) {
publisher.formatter = formatter;
}

@Override
protected Optional<ChecksPublisher> createPublisher(final Run<?, ?> run, final TaskListener listener) {
publisher.listener = listener;
return Optional.of(publisher);
}

@Override
protected Optional<ChecksPublisher> createPublisher(final Job<?, ?> job, final TaskListener listener) {
publisher.listener = listener;
return Optional.of(publisher);
}
}

/**
* Defines how to format a {@link ChecksDetails} to {@link String}.
*/
@FunctionalInterface
public interface Formatter {
/**
* Formats the {@code details}.
*
* @param details
* details to format.
* @return formatted string
*/
String format(ChecksDetails details);
}
}