Files
github-api/src/test/java/org/kohsuke/github/GitHubStaticTest.java
Liam Newman e0aee9f361 Expose MappingReader and MappingWriter
Jenkins Blue Ocean made interesting design choices relating github-api interactions.

They mostly reused the existing API and OM, but in a few places they chose to
implement their own object mapping independent of this project. This is fine
as long as nothing in this project ever changes, including internals such
as ObjectMapper configuration or behavior.

Recent release have made changes to those internals which break assumptions made
in Blue Ocean.

This change exposes this project's MappingReader and MappingWriter to allow
for a fix to Blue Ocean requiring only minimal changes.

This doesn't prevent future changes from breaking Blue Ocean but at least makes
them much less likely.

Fixes #780
2020-04-15 16:39:59 -07:00

166 lines
7.3 KiB
Java

package org.kohsuke.github;
import org.junit.Test;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.TimeZone;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.core.Is.is;
/**
* Unit test for {@link GitHub} static helpers.
*
* @author Liam Newman
*/
public class GitHubStaticTest extends AbstractGitHubWireMockTest {
@Test
public void timeRoundTrip() throws Exception {
Instant instantNow = Instant.now();
Date instantSeconds = Date.from(instantNow.truncatedTo(ChronoUnit.SECONDS));
Date instantMillis = Date.from(instantNow.truncatedTo(ChronoUnit.MILLIS));
// if we happen to land exactly on zero milliseconds, add 1 milli
if (instantSeconds.equals(instantMillis)) {
instantMillis = Date.from(instantNow.plusMillis(1).truncatedTo(ChronoUnit.MILLIS));
}
// TODO: other formats
String instantFormatSlash = formatDate(instantMillis, "yyyy/MM/dd HH:mm:ss ZZZZ");
String instantFormatDash = formatDate(instantMillis, "yyyy-MM-dd'T'HH:mm:ss'Z'");
String instantFormatMillis = formatDate(instantMillis, "yyyy-MM-dd'T'HH:mm:ss.S'Z'");
String instantSecondsFormatMillis = formatDate(instantSeconds, "yyyy-MM-dd'T'HH:mm:ss.S'Z'");
String instantBadFormat = formatDate(instantMillis, "yy-MM-dd'T'HH:mm'Z'");
assertThat(GitHubClient.parseDate(GitHubClient.printDate(instantSeconds)),
equalTo(GitHubClient.parseDate(GitHubClient.printDate(instantMillis))));
assertThat(instantSeconds, equalTo(GitHubClient.parseDate(GitHubClient.printDate(instantSeconds))));
// printDate will truncate to the nearest second, so it should not be equal
assertThat(instantMillis, not(equalTo(GitHubClient.parseDate(GitHubClient.printDate(instantMillis)))));
assertThat(instantSeconds, equalTo(GitHubClient.parseDate(instantFormatSlash)));
assertThat(instantSeconds, equalTo(GitHubClient.parseDate(instantFormatDash)));
// This parser does not truncate to the nearest second, so it will be equal
assertThat(instantMillis, equalTo(GitHubClient.parseDate(instantFormatMillis)));
assertThat(instantSeconds, equalTo(GitHubClient.parseDate(instantSecondsFormatMillis)));
try {
GitHubClient.parseDate(instantBadFormat);
fail("Bad time format should throw.");
} catch (IllegalStateException e) {
assertThat(e.getMessage(), equalTo("Unable to parse the timestamp: " + instantBadFormat));
}
}
@Test
public void testGitHubRateLimitShouldReplaceRateLimit() throws Exception {
GHRateLimit.Record unknown0 = GHRateLimit.Unknown().getCore();
GHRateLimit.Record unknown1 = GHRateLimit.Unknown().getCore();
GHRateLimit.Record record0 = new GHRateLimit.Record(10, 10, 10L);
GHRateLimit.Record record1 = new GHRateLimit.Record(10, 9, 10L);
GHRateLimit.Record record2 = new GHRateLimit.Record(10, 2, 10L);
GHRateLimit.Record record3 = new GHRateLimit.Record(10, 10, 20L);
GHRateLimit.Record record4 = new GHRateLimit.Record(10, 5, 20L);
Thread.sleep(2000);
GHRateLimit.Record recordWorst = new GHRateLimit.Record(Integer.MAX_VALUE, Integer.MAX_VALUE, Long.MIN_VALUE);
GHRateLimit.Record record00 = new GHRateLimit.Record(10, 10, 10L);
GHRateLimit.Record unknown2 = GHRateLimit.Unknown().getCore();
// Rate-limit records maybe created and returned in different orders.
// We should update to the regular records over unknowns.
// After that, we should update to the candidate if its limit is lower or its reset is later.
assertThat("Equivalent unknown should not replace", GitHubClient.shouldReplace(unknown0, unknown1), is(false));
assertThat("Equivalent unknown should not replace", GitHubClient.shouldReplace(unknown1, unknown0), is(false));
assertThat("Later unknown should replace earlier", GitHubClient.shouldReplace(unknown2, unknown0), is(true));
assertThat("Earlier unknown should not replace later",
GitHubClient.shouldReplace(unknown0, unknown2),
is(false));
assertThat("Worst record should replace later unknown",
GitHubClient.shouldReplace(recordWorst, unknown1),
is(true));
assertThat("Unknown should not replace worst record",
GitHubClient.shouldReplace(unknown1, recordWorst),
is(false));
assertThat("Earlier record should replace later worst",
GitHubClient.shouldReplace(record0, recordWorst),
is(true));
assertThat("Later worst record should not replace earlier",
GitHubClient.shouldReplace(recordWorst, record0),
is(false));
assertThat("Equivalent record should not replace", GitHubClient.shouldReplace(record0, record00), is(false));
assertThat("Equivalent record should not replace", GitHubClient.shouldReplace(record00, record0), is(false));
assertThat("Lower limit record should replace higher", GitHubClient.shouldReplace(record1, record0), is(true));
assertThat("Lower limit record should replace higher", GitHubClient.shouldReplace(record2, record1), is(true));
assertThat("Higher limit record should not replace lower",
GitHubClient.shouldReplace(record1, record2),
is(false));
assertThat("Higher limit record with later reset should replace lower",
GitHubClient.shouldReplace(record3, record2),
is(true));
assertThat("Lower limit record with later reset should replace higher",
GitHubClient.shouldReplace(record4, record1),
is(true));
assertThat("Lower limit record with earlier reset should not replace higher",
GitHubClient.shouldReplace(record2, record4),
is(false));
}
@Test
public void testMappingReaderWriter() throws Exception {
// This test ensures that data objects can be written and read in a raw form from string.
// This behavior is completely unsupported and should not be used but given that some
// clients, such as Jenkins Blue Ocean, have already implemented their own Jackson
// Reader and Writer that bind this library's data objects from outside this library
// this makes sure they don't break.
GHRepository repo = getTempRepository();
assertThat(repo.root, not(nullValue()));
String repoString = GitHub.getMappingObjectWriter().writeValueAsString(repo);
assertThat(repoString, not(nullValue()));
assertThat(repoString, containsString("testMappingReaderWriter"));
GHRepository readRepo = GitHub.getMappingObjectReader().forType(GHRepository.class).readValue(repoString);
// This should never happen if these methods aren't used
assertThat(readRepo.root, nullValue());
String readRepoString = GitHub.getMappingObjectWriter().writeValueAsString(readRepo);
assertThat(readRepoString, equalTo(repoString));
}
static String formatDate(Date dt, String format) {
SimpleDateFormat df = new SimpleDateFormat(format);
df.setTimeZone(TimeZone.getTimeZone("GMT"));
return df.format(dt);
}
}