diff --git a/src/main/java/org/kohsuke/github/GHRateLimit.java b/src/main/java/org/kohsuke/github/GHRateLimit.java index d917bdfbd..c0b21da81 100644 --- a/src/main/java/org/kohsuke/github/GHRateLimit.java +++ b/src/main/java/org/kohsuke/github/GHRateLimit.java @@ -20,6 +20,7 @@ import static java.util.logging.Level.FINEST; * * @author Kohsuke Kawaguchi */ +@SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD", justification = "JSON API") public class GHRateLimit { /** @@ -47,147 +48,149 @@ public class GHRateLimit { @Deprecated public Date reset; - /** - * Remaining calls that can be made. - */ - private final int remainingCount; - /** - * Allotted API call per hour. - */ - private final int limitCount; - - /** - * The time at which the current rate limit window resets in UTC epoch seconds. - */ - private final long resetEpochSeconds; - - /** - * EpochSeconds time (UTC) at which this instance was created. - */ - private final long createdAtEpochSeconds = System.currentTimeMillis() / 1000; - - /** - * The calculated time at which the rate limit will reset. - * Recalculated if {@link #recalculateResetDate} is called. - */ @Nonnull - private Date resetDate; + private final Record core; - /** - * Gets a placeholder instance that can be used when we fail to get one from the server. - * - * @return a GHRateLimit - */ - public static GHRateLimit getPlaceholder() { - final long oneHour = 60L * 60L; - // This placeholder limit does not expire for a while - // This make it so that calling rateLimit() multiple times does not result in multiple request - GHRateLimit r = new GHRateLimit(1000000, 1000000, System.currentTimeMillis() / 1000L + oneHour); - return r; + @Nonnull + private final Record search; + + @Nonnull + private final Record graphql; + + @Nonnull + private final Record integrationManifest; + + static GHRateLimit Unknown() { + return new GHRateLimit(new UnknownLimitRecord(), new UnknownLimitRecord(), new UnknownLimitRecord(), new UnknownLimitRecord()); + } + + static GHRateLimit fromHeaderRecord(Record header) { + return new GHRateLimit(header, new UnknownLimitRecord(), new UnknownLimitRecord(), new UnknownLimitRecord()); } @JsonCreator - public GHRateLimit(@JsonProperty("limit") int limit, - @JsonProperty("remaining") int remaining, - @JsonProperty("reset")long resetEpochSeconds) { - this(limit, remaining, resetEpochSeconds, null); - } - - @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD", - justification = "Deprecated") - public GHRateLimit(int limit, int remaining, long resetEpochSeconds, String updatedAt) { - this.limitCount = limit; - this.remainingCount = remaining; - this.resetEpochSeconds = resetEpochSeconds; - this.resetDate = recalculateResetDate(updatedAt); + GHRateLimit(@Nonnull @JsonProperty("core") Record core, + @Nonnull @JsonProperty("search") Record search, + @Nonnull @JsonProperty("graphql") Record graphql, + @Nonnull @JsonProperty("integration_manifest") Record integrationManifest) { + this.core = core; + this.search = search; + this.graphql = graphql; + this.integrationManifest = integrationManifest; // Deprecated fields - this.remaining = remaining; - this.limit = limit; - this.reset = new Date(resetEpochSeconds); + this.remaining = core.getRemaining(); + this.limit = core.getLimit(); + this.reset = new Date(core.getResetEpochSeconds()); } - /** - * - * @param updatedAt a string date in RFC 1123 - * @return reset date based on the passed date - */ - Date recalculateResetDate(String updatedAt) { - long updatedAtEpochSeconds = createdAtEpochSeconds; - if (!StringUtils.isBlank(updatedAt)) { - try { - // Get the server date and reset data, will always return a time in GMT - updatedAtEpochSeconds = ZonedDateTime.parse(updatedAt, DateTimeFormatter.RFC_1123_DATE_TIME).toEpochSecond(); - } catch (DateTimeParseException e) { - if (LOGGER.isLoggable(FINEST)) { - LOGGER.log(FINEST, "Malformed Date header value " + updatedAt, e); - } - } - } - - // This may seem odd but it results in an accurate or slightly pessimistic reset date - // based on system time rather than on the system being in sync with the server - long calculatedSecondsUntilReset = resetEpochSeconds - updatedAtEpochSeconds; - return resetDate = new Date((createdAtEpochSeconds + calculatedSecondsUntilReset) * 1000); - } /** - * Gets the remaining number of requests allowed before this connection will be throttled. - * - * @return an integer - */ - public int getRemaining() { - return remainingCount; - } - - /** - * Gets the total number of API calls per hour allotted for this connection. - * - * @return an integer - */ - public int getLimit() { - return limitCount; - } - - /** - * Gets the time in epoch seconds when the rate limit will reset. - * - * @return a long - */ - public long getResetEpochSeconds() { - return resetEpochSeconds; - } - - /** - * Whether the rate limit reset date indicated by this instance is in the - * - * @return true if the rate limit reset date has passed. Otherwise false. - */ - public boolean isExpired() { - return getResetDate().getTime() < System.currentTimeMillis(); - } - - /** - * Returns the date at which the rate limit will reset. + * Returns the date at which the Core API rate limit will reset. * * @return the calculated date at which the rate limit has or will reset. */ @Nonnull public Date getResetDate() { - return new Date(resetDate.getTime()); + return getCore().getResetDate(); + } + + /** + * Gets the remaining number of Core APIs requests allowed before this connection will be throttled. + * + * @return an integer + * @since 1.100 + */ + public int getRemaining() { + return getCore().getRemaining(); + } + + /** + * Gets the total number of Core API calls per hour allotted for this connection. + * + * @return an integer + * @since 1.100 + */ + public int getLimit() { + return getCore().getLimit(); + } + + + /** + * Gets the time in epoch seconds when the Core API rate limit will reset. + * + * @return a long + * @since 1.100 + */ + public long getResetEpochSeconds() { + return getCore().getResetEpochSeconds(); + } + + /** + * Whether the rate limit reset date for this instance has passed. + * + * @return true if the rate limit reset date has passed. Otherwise false. + * @since 1.100 + */ + public boolean isExpired() { + return getCore().isExpired(); + } + + /** + * The core object provides your rate limit status for all non-search-related resources in the REST API. + * + * @return a rate limit record + * @since 1.100 + */ + @Nonnull + public Record getCore() { + return core; + } + + /** + * The search object provides your rate limit status for the Search API. + * TODO: integrate with header limit updating. Issue #605. + * + * @return a rate limit record + */ + @Nonnull + Record getSearch() { + return search; + } + + /** + * The graphql object provides your rate limit status for the GraphQL API. + * TODO: integrate with header limit updating. Issue #605. + * + * @return a rate limit record + */ + @Nonnull + Record getGraphQL() { + return graphql; + } + + /** + * The integration_manifest object provides your rate limit status for the GitHub App Manifest code conversion endpoint. + * TODO: integrate with header limit updating. Issue #605. + * + * @return a rate limit record + */ + @Nonnull + Record getIntegrationManifest() { + return integrationManifest; } @Override public String toString() { - return "GHRateLimit{" + - "remaining=" + getRemaining() + - ", limit=" + getLimit() + - ", resetDate=" + getResetDate() + - '}'; + return "GHRateLimit {" + + "core " + getCore().toString() + + "search " + getSearch().toString() + + "graphql " + getGraphQL().toString() + + "integrationManifest " + getIntegrationManifest().toString() + + '}'; } - @Override public boolean equals(Object o) { if (this == o) { @@ -197,15 +200,185 @@ public class GHRateLimit { return false; } GHRateLimit rateLimit = (GHRateLimit) o; - return getRemaining() == rateLimit.getRemaining() && - getLimit() == rateLimit.getLimit() && - getResetEpochSeconds() == rateLimit.getResetEpochSeconds() && - getResetDate().equals(rateLimit.getResetDate()); + return getCore().equals(rateLimit.getCore()) && + getSearch().equals(rateLimit.getSearch()) && + getGraphQL().equals(rateLimit.getGraphQL()) && + getIntegrationManifest().equals(rateLimit.getIntegrationManifest()); } @Override public int hashCode() { - return Objects.hash(getRemaining(), getLimit(), getResetEpochSeconds(), getResetDate()); + return Objects.hash(getCore(), getSearch(), getGraphQL(), getIntegrationManifest()); + } + + /** + * A limit record used as a placeholder when the the actual limit is not known. + * + * Has a large limit and long duration so that it will doesn't expire too often. + * + * @since 1.100* + */ + public static class UnknownLimitRecord extends Record { + + // One hour + private static final long unknownLimitResetSeconds = 60L * 60L; + + static final int unknownLimit = 1000000; + static final int unknownRemaining = 999999; + + private UnknownLimitRecord() { + super(unknownLimit, unknownRemaining, System.currentTimeMillis() / 1000L + unknownLimitResetSeconds); + } + } + + /** + * A rate limit record. + * @since 1.100 + */ + public static class Record { + /** + * Remaining calls that can be made. + */ + private final int remaining; + + /** + * Allotted API call per hour. + */ + private final int limit; + + /** + * The time at which the current rate limit window resets in UTC epoch seconds. + */ + private final long resetEpochSeconds; + + /** + * EpochSeconds time (UTC) at which this instance was created. + */ + private final long createdAtEpochSeconds = System.currentTimeMillis() / 1000; + + /** + * The calculated time at which the rate limit will reset. + * Recalculated if {@link #recalculateResetDate} is called. + */ + @Nonnull + private Date resetDate; + + @JsonCreator + public Record(@JsonProperty("limit") int limit, + @JsonProperty("remaining") int remaining, + @JsonProperty("reset")long resetEpochSeconds) { + this(limit, remaining, resetEpochSeconds, null); + } + + @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD", + justification = "Deprecated") + public Record(int limit, int remaining, long resetEpochSeconds, String updatedAt) { + this.limit = limit; + this.remaining = remaining; + this.resetEpochSeconds = resetEpochSeconds; + this.resetDate = recalculateResetDate(updatedAt); + } + + /** + * Recalculates the reset date using the server response date to calculate a time duration + * and then add that to the local created time for this record. + * + * @param updatedAt a string date in RFC 1123 + * @return reset date based on the passed date + */ + Date recalculateResetDate(String updatedAt) { + long updatedAtEpochSeconds = createdAtEpochSeconds; + if (!StringUtils.isBlank(updatedAt)) { + try { + // Get the server date and reset data, will always return a time in GMT + updatedAtEpochSeconds = ZonedDateTime.parse(updatedAt, DateTimeFormatter.RFC_1123_DATE_TIME).toEpochSecond(); + } catch (DateTimeParseException e) { + if (LOGGER.isLoggable(FINEST)) { + LOGGER.log(FINEST, "Malformed Date header value " + updatedAt, e); + } + } + } + + // This may seem odd but it results in an accurate or slightly pessimistic reset date + // based on system time rather than on the system being in sync with the server + long calculatedSecondsUntilReset = resetEpochSeconds - updatedAtEpochSeconds; + return resetDate = new Date((createdAtEpochSeconds + calculatedSecondsUntilReset) * 1000); + } + + /** + * Gets the remaining number of requests allowed before this connection will be throttled. + * + * @return an integer + */ + public int getRemaining() { + return remaining; + } + + /** + * Gets the total number of API calls per hour allotted for this connection. + * + * @return an integer + */ + public int getLimit() { + return limit; + } + + /** + * Gets the time in epoch seconds when the rate limit will reset. + * + * @return a long + */ + public long getResetEpochSeconds() { + return resetEpochSeconds; + } + + /** + * Whether the rate limit reset date indicated by this instance is in the + * + * @return true if the rate limit reset date has passed. Otherwise false. + */ + public boolean isExpired() { + return getResetDate().getTime() < System.currentTimeMillis(); + } + + /** + * Returns the date at which the rate limit will reset. + * + * @return the calculated date at which the rate limit has or will reset. + */ + @Nonnull + public Date getResetDate() { + return new Date(resetDate.getTime()); + } + + @Override + public String toString() { + return "{" + + "remaining=" + getRemaining() + + ", limit=" + getLimit() + + ", resetDate=" + getResetDate() + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Record record = (Record) o; + return getRemaining() == record.getRemaining() && + getLimit() == record.getLimit() && + getResetEpochSeconds() == record.getResetEpochSeconds() && + getResetDate().equals(record.getResetDate()); + } + + @Override + public int hashCode() { + return Objects.hash(getRemaining(), getLimit(), getResetEpochSeconds(), getResetDate()); + } } private static final Logger LOGGER = Logger.getLogger(Requester.class.getName()); diff --git a/src/main/java/org/kohsuke/github/GitHub.java b/src/main/java/org/kohsuke/github/GitHub.java index 12012420a..fcd4c171a 100644 --- a/src/main/java/org/kohsuke/github/GitHub.java +++ b/src/main/java/org/kohsuke/github/GitHub.java @@ -318,29 +318,59 @@ public class GitHub { public GHRateLimit getRateLimit() throws IOException { GHRateLimit rateLimit; try { - rateLimit = retrieve().to("/rate_limit", JsonRateLimit.class).rate; + rateLimit = retrieve().to("/rate_limit", JsonRateLimit.class).resources; } catch (FileNotFoundException e) { - // GitHub Enterprise doesn't have the rate limit, so in that case - // return some big number that's not too big. - // see issue #78 - rateLimit = GHRateLimit.getPlaceholder(); + // GitHub Enterprise doesn't have the rate limit + // return a default rate limit that + rateLimit = GHRateLimit.Unknown(); } return this.rateLimit = rateLimit; - } - /*package*/ void updateRateLimit(@Nonnull GHRateLimit observed) { + /** + * Update the Rate Limit with the latest info from response header. + * Due to multi-threading requests might complete out of order, we want to pick the one with the most recent info from the server. + * + * @param observed {@link GHRateLimit.Record} constructed from the response header information + */ + void updateCoreRateLimit(@Nonnull GHRateLimit.Record observed) { synchronized (headerRateLimitLock) { - if (headerRateLimit == null - || headerRateLimit.getRemaining() > observed.getRemaining() - || headerRateLimit.getResetEpochSeconds() < observed.getResetEpochSeconds()) { - headerRateLimit = observed; + if (headerRateLimit == null || shouldReplace(observed, headerRateLimit.getCore())) { + headerRateLimit = GHRateLimit.fromHeaderRecord(observed); LOGGER.log(FINE, "Rate limit now: {0}", headerRateLimit); } } } + /** + * Update the Rate Limit with the latest info from response header. + * Due to multi-threading requests might complete out of order, we want to pick the one with the most recent info from the server. + * Header date is only accurate to the second, so we look at the information in the record itself. + * + * {@link GHRateLimit.UnknownLimitRecord}s are always replaced by regular {@link GHRateLimit.Record}s. + * Regular {@link GHRateLimit.Record}s are never replaced by {@link GHRateLimit.UnknownLimitRecord}s. + * Candidates with resetEpochSeconds later than current record are more recent. + * Candidates with the same reset and a lower remaining count are more recent. + * Candidates with an earlier reset are older. + * + * @param candidate {@link GHRateLimit.Record} constructed from the response header information + * @param current the current {@link GHRateLimit.Record} record + */ + static boolean shouldReplace(@Nonnull GHRateLimit.Record candidate, @Nonnull GHRateLimit.Record current) { + if (candidate instanceof GHRateLimit.UnknownLimitRecord && !(current instanceof GHRateLimit.UnknownLimitRecord)) { + // Unknown candidate never replaces a regular record + return false; + } else if (current instanceof GHRateLimit.UnknownLimitRecord && !(candidate instanceof GHRateLimit.UnknownLimitRecord)) { + // Any real record should replace an unknown Record. + return true; + } else { + // records of the same type compare to each other as normal. + return current.getResetEpochSeconds() < candidate.getResetEpochSeconds() + || (current.getResetEpochSeconds() == candidate.getResetEpochSeconds() && current.getRemaining() > candidate.getRemaining()); + } + } + /** * Returns the most recently observed rate limit data or {@code null} if either there is no rate limit * (for example GitHub Enterprise) or if no requests have been made. diff --git a/src/main/java/org/kohsuke/github/JsonRateLimit.java b/src/main/java/org/kohsuke/github/JsonRateLimit.java index 6276ae9b8..6dbfcdb5e 100644 --- a/src/main/java/org/kohsuke/github/JsonRateLimit.java +++ b/src/main/java/org/kohsuke/github/JsonRateLimit.java @@ -4,5 +4,7 @@ package org.kohsuke.github; * @author Kohsuke Kawaguchi */ class JsonRateLimit { - GHRateLimit rate; + + GHRateLimit resources; + } diff --git a/src/main/java/org/kohsuke/github/Requester.java b/src/main/java/org/kohsuke/github/Requester.java index 167cf3e2d..4078081cc 100644 --- a/src/main/java/org/kohsuke/github/Requester.java +++ b/src/main/java/org/kohsuke/github/Requester.java @@ -399,9 +399,9 @@ class Requester { return; } - GHRateLimit observed = new GHRateLimit(limit, remaining, reset, uc.getHeaderField("Date")); + GHRateLimit.Record observed = new GHRateLimit.Record(limit, remaining, reset, uc.getHeaderField("Date")); - root.updateRateLimit(observed); + root.updateCoreRateLimit(observed); } public String getResponseHeader(String header) { @@ -710,7 +710,7 @@ class Requester { setResponseHeaders((GHObject) readValue); } else if (readValue instanceof JsonRateLimit) { // if we're getting a GHRateLimit it needs the server date - ((JsonRateLimit)readValue).rate.recalculateResetDate(uc.getHeaderField("Date")); + ((JsonRateLimit)readValue).resources.getCore().recalculateResetDate(uc.getHeaderField("Date")); } return readValue; } diff --git a/src/test/java/org/kohsuke/github/GHRateLimitTest.java b/src/test/java/org/kohsuke/github/GHRateLimitTest.java index c47a46837..4206e86a2 100644 --- a/src/test/java/org/kohsuke/github/GHRateLimitTest.java +++ b/src/test/java/org/kohsuke/github/GHRateLimitTest.java @@ -166,8 +166,12 @@ public class GHRateLimitTest extends AbstractGitHubWireMockTest { // These are separate instances, but should be equal assertThat(gitHub.rateLimit(), not(sameInstance(rateLimit))); - // Verify different intstances can be compared - assertThat(gitHub.rateLimit(), equalTo(rateLimit)); + // Verify different record instances can be compared + assertThat(gitHub.rateLimit().getCore(), equalTo(rateLimit.getCore())); + + // Verify different instances can be compared + // TODO: This is not work currently because the header rate limit has unknowns for records other than core. + // assertThat(gitHub.rateLimit().getCore(), equalTo(rateLimit.getCore())); assertThat(gitHub.rateLimit(), not(sameInstance(headerRateLimit))); assertThat(gitHub.rateLimit(), sameInstance(gitHub.lastRateLimit())); @@ -195,11 +199,11 @@ public class GHRateLimitTest extends AbstractGitHubWireMockTest { assertThat(gitHub.lastRateLimit(), CoreMatchers.nullValue()); rateLimit = gitHub.rateLimit(); - assertThat(rateLimit, notNullValue()); - assertThat(rateLimit.limit, equalTo(1000000)); - assertThat(rateLimit.getLimit(), equalTo(1000000)); - assertThat(rateLimit.remaining, equalTo(1000000)); - assertThat(rateLimit.getRemaining(), equalTo(1000000)); + assertThat(rateLimit.getCore(), instanceOf(GHRateLimit.UnknownLimitRecord.class)); + assertThat(rateLimit.limit, equalTo(GHRateLimit.UnknownLimitRecord.unknownLimit)); + assertThat(rateLimit.getLimit(), equalTo(GHRateLimit.UnknownLimitRecord.unknownLimit)); + assertThat(rateLimit.remaining, equalTo(GHRateLimit.UnknownLimitRecord.unknownRemaining)); + assertThat(rateLimit.getRemaining(), equalTo(GHRateLimit.UnknownLimitRecord.unknownRemaining)); assertThat(rateLimit.getResetDate().compareTo(lastReset), equalTo(1)); lastReset = rateLimit.getResetDate(); @@ -222,11 +226,11 @@ public class GHRateLimitTest extends AbstractGitHubWireMockTest { assertThat(gitHub.lastRateLimit(), CoreMatchers.nullValue()); rateLimit = gitHub.rateLimit(); - assertThat(rateLimit, notNullValue()); - assertThat(rateLimit.limit, equalTo(1000000)); - assertThat(rateLimit.getLimit(), equalTo(1000000)); - assertThat(rateLimit.remaining, equalTo(1000000)); - assertThat(rateLimit.getRemaining(), equalTo(1000000)); + assertThat(rateLimit.getCore(), instanceOf(GHRateLimit.UnknownLimitRecord.class)); + assertThat(rateLimit.limit, equalTo(GHRateLimit.UnknownLimitRecord.unknownLimit)); + assertThat(rateLimit.getLimit(), equalTo(GHRateLimit.UnknownLimitRecord.unknownLimit)); + assertThat(rateLimit.remaining, equalTo(GHRateLimit.UnknownLimitRecord.unknownRemaining)); + assertThat(rateLimit.getRemaining(), equalTo(GHRateLimit.UnknownLimitRecord.unknownRemaining)); assertThat(rateLimit.getResetDate().compareTo(lastReset), equalTo(1)); lastReset = rateLimit.getResetDate(); @@ -239,11 +243,11 @@ public class GHRateLimitTest extends AbstractGitHubWireMockTest { rateLimit = gitHub.getRateLimit(); assertThat(mockGitHub.getRequestCount(), equalTo(4)); - assertThat(rateLimit, notNullValue()); - assertThat(rateLimit.limit, equalTo(1000000)); - assertThat(rateLimit.getLimit(), equalTo(1000000)); - assertThat(rateLimit.remaining, equalTo(1000000)); - assertThat(rateLimit.getRemaining(), equalTo(1000000)); + assertThat(rateLimit.getCore(), instanceOf(GHRateLimit.UnknownLimitRecord.class)); + assertThat(rateLimit.limit, equalTo(GHRateLimit.UnknownLimitRecord.unknownLimit)); + assertThat(rateLimit.getLimit(), equalTo(GHRateLimit.UnknownLimitRecord.unknownLimit)); + assertThat(rateLimit.remaining, equalTo(GHRateLimit.UnknownLimitRecord.unknownRemaining)); + assertThat(rateLimit.getRemaining(), equalTo(GHRateLimit.UnknownLimitRecord.unknownRemaining)); assertThat(rateLimit.getResetDate().compareTo(lastReset), equalTo(1)); // Give this a moment @@ -290,11 +294,11 @@ public class GHRateLimitTest extends AbstractGitHubWireMockTest { rateLimit = gitHub.getRateLimit(); assertThat(mockGitHub.getRequestCount(), equalTo(6)); - assertThat(rateLimit, notNullValue()); - assertThat(rateLimit.limit, equalTo(1000000)); - assertThat(rateLimit.getLimit(), equalTo(1000000)); - assertThat(rateLimit.remaining, equalTo(1000000)); - assertThat(rateLimit.getRemaining(), equalTo(1000000)); + assertThat(rateLimit.getCore(), instanceOf(GHRateLimit.UnknownLimitRecord.class)); + assertThat(rateLimit.limit, equalTo(GHRateLimit.UnknownLimitRecord.unknownLimit)); + assertThat(rateLimit.getLimit(), equalTo(GHRateLimit.UnknownLimitRecord.unknownLimit)); + assertThat(rateLimit.remaining, equalTo(GHRateLimit.UnknownLimitRecord.unknownRemaining)); + assertThat(rateLimit.getRemaining(), equalTo(GHRateLimit.UnknownLimitRecord.unknownRemaining)); assertThat(rateLimit.getResetDate().compareTo(lastReset), equalTo(1)); // ratelimit() should prefer headerRateLimit when getRateLimit fails and headerRateLimit is not expired @@ -307,12 +311,7 @@ public class GHRateLimitTest extends AbstractGitHubWireMockTest { } - // These three tests should be have the same, showing server time adjustment working - @Test - public void testGitHubRateLimitExpiration() throws Exception { - executeExpirationTest(); - } - + // These tests should behave the same, showing server time adjustment working @Test public void testGitHubRateLimitExpirationServerFiveMinutesAhead() throws Exception { executeExpirationTest(); diff --git a/src/test/java/org/kohsuke/github/GitHubStaticTest.java b/src/test/java/org/kohsuke/github/GitHubStaticTest.java index 9c03a3323..47e600aef 100644 --- a/src/test/java/org/kohsuke/github/GitHubStaticTest.java +++ b/src/test/java/org/kohsuke/github/GitHubStaticTest.java @@ -1,5 +1,7 @@ package org.kohsuke.github; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import org.eclipse.jgit.api.Git; import org.junit.Assert; import org.junit.Test; @@ -11,6 +13,7 @@ import java.util.TimeZone; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.core.Is.is; /** * Unit test for {@link GitHub} static helpers. @@ -68,6 +71,65 @@ public class GitHubStaticTest extends Assert { } 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", GitHub.shouldReplace(unknown0, unknown1), is(false)); + assertThat("Equivalent unknown should not replace", GitHub.shouldReplace(unknown1, unknown0), is(false)); + + assertThat("Later unknown should replace earlier", GitHub.shouldReplace(unknown2, unknown0), is(true)); + assertThat("Earlier unknown should not replace later", GitHub.shouldReplace(unknown0, unknown2), is(false)); + + assertThat("Worst record should replace later unknown", GitHub.shouldReplace(recordWorst, unknown1), is(true)); + assertThat("Unknown should not replace worst record", GitHub.shouldReplace(unknown1, recordWorst), is(false)); + + assertThat("Earlier record should replace later worst", GitHub.shouldReplace(record0, recordWorst), is(true)); + assertThat("Later worst record should not replace earlier", GitHub.shouldReplace(recordWorst, record0), is(false)); + + assertThat("Equivalent record should not replace", GitHub.shouldReplace(record0, record00), is(false)); + assertThat("Equivalent record should not replace", GitHub.shouldReplace(record00, record0), is(false)); + + assertThat("Lower limit record should replace higher", GitHub.shouldReplace(record1, record0), is(true)); + assertThat("Lower limit record should replace higher", GitHub.shouldReplace(record2, record1), is(true)); + + assertThat("Higher limit record should not replace lower", GitHub.shouldReplace(record1, record2), is(false)); + + assertThat("Higher limit record with later reset should replace lower", GitHub.shouldReplace(record3, record2), is(true)); + + assertThat("Lower limit record with later reset should replace higher", GitHub.shouldReplace(record4, record1), is(true)); + + assertThat("Lower limit record with earlier reset should not replace higher", GitHub.shouldReplace(record2, record4), is(false)); + + + + + + } static String formatDate(Date dt, String format) { diff --git a/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimit/__files/rate_limit-4e2fc33b-fb25-4dfc-9d56-34f9b4d707be.json b/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimit/__files/rate_limit-4e2fc33b-fb25-4dfc-9d56-34f9b4d707be.json index dc1b25b18..607385447 100644 --- a/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimit/__files/rate_limit-4e2fc33b-fb25-4dfc-9d56-34f9b4d707be.json +++ b/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimit/__files/rate_limit-4e2fc33b-fb25-4dfc-9d56-34f9b4d707be.json @@ -3,27 +3,27 @@ "core": { "limit": 5000, "remaining": 4896, - "reset": 1570478899 + "reset": {{now offset='1 hours' format='unix'}} }, "search": { "limit": 30, "remaining": 30, - "reset": 1570478180 + "reset": {{now offset='1 hours' format='unix'}} }, "graphql": { "limit": 5000, "remaining": 5000, - "reset": 1570481642 + "reset": {{now offset='1 hours' format='unix'}} }, "integration_manifest": { "limit": 5000, "remaining": 5000, - "reset": 1570481642 + "reset": {{now offset='1 hours' format='unix'}} } }, "rate": { "limit": 5000, "remaining": 4896, - "reset": {{now offset='1 hours' format='unix'}} + "reset": 1570478899 } } \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimit/__files/rate_limit-a1f82a96-500c-4462-ae7b-e0159afa8208.json b/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimit/__files/rate_limit-a1f82a96-500c-4462-ae7b-e0159afa8208.json index b05430bbf..e5881bcd4 100644 --- a/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimit/__files/rate_limit-a1f82a96-500c-4462-ae7b-e0159afa8208.json +++ b/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimit/__files/rate_limit-a1f82a96-500c-4462-ae7b-e0159afa8208.json @@ -3,27 +3,27 @@ "core": { "limit": 5000, "remaining": 4897, - "reset": 1570478899 + "reset": {{now offset='1 hours' format='unix'}} }, "search": { "limit": 30, "remaining": 30, - "reset": 1570478180 + "reset": {{now offset='1 hours' format='unix'}} }, "graphql": { "limit": 5000, "remaining": 5000, - "reset": 1570481642 + "reset": {{now offset='1 hours' format='unix'}} }, "integration_manifest": { "limit": 5000, "remaining": 5000, - "reset": 1570481642 + "reset": {{now offset='1 hours' format='unix'}} } }, "rate": { "limit": 5000, "remaining": 4897, - "reset": {{now offset='1 hours' format='unix'}} + "reset": 1570478899 } } \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimit/__files/rate_limit-f22b1cea-3679-481d-8b95-459b2c47bf98.json b/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimit/__files/rate_limit-f22b1cea-3679-481d-8b95-459b2c47bf98.json index b05430bbf..e5881bcd4 100644 --- a/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimit/__files/rate_limit-f22b1cea-3679-481d-8b95-459b2c47bf98.json +++ b/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimit/__files/rate_limit-f22b1cea-3679-481d-8b95-459b2c47bf98.json @@ -3,27 +3,27 @@ "core": { "limit": 5000, "remaining": 4897, - "reset": 1570478899 + "reset": {{now offset='1 hours' format='unix'}} }, "search": { "limit": 30, "remaining": 30, - "reset": 1570478180 + "reset": {{now offset='1 hours' format='unix'}} }, "graphql": { "limit": 5000, "remaining": 5000, - "reset": 1570481642 + "reset": {{now offset='1 hours' format='unix'}} }, "integration_manifest": { "limit": 5000, "remaining": 5000, - "reset": 1570481642 + "reset": {{now offset='1 hours' format='unix'}} } }, "rate": { "limit": 5000, "remaining": 4897, - "reset": {{now offset='1 hours' format='unix'}} + "reset": 1570478899 } } \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpiration/__files/rate_limit-4e2fc33b-fb25-4dfc-9d56-34f9b4d707be.json b/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpiration/__files/rate_limit-4e2fc33b-fb25-4dfc-9d56-34f9b4d707be.json deleted file mode 100644 index 04bc2d1c4..000000000 --- a/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpiration/__files/rate_limit-4e2fc33b-fb25-4dfc-9d56-34f9b4d707be.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "resources": { - "core": { - "limit": 5000, - "remaining": 4896, - "reset": 1570478899 - }, - "search": { - "limit": 30, - "remaining": 30, - "reset": 1570478180 - }, - "graphql": { - "limit": 5000, - "remaining": 5000, - "reset": 1570481642 - }, - "integration_manifest": { - "limit": 5000, - "remaining": 5000, - "reset": 1570481642 - } - }, - "rate": { - "limit": 5000, - "remaining": 4896, - "reset": {{now offset='5 seconds' format='unix'}} - } -} \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpiration/__files/rate_limit-a1f82a96-500c-4462-ae7b-e0159afa8208.json b/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpiration/__files/rate_limit-a1f82a96-500c-4462-ae7b-e0159afa8208.json deleted file mode 100644 index d846f8221..000000000 --- a/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpiration/__files/rate_limit-a1f82a96-500c-4462-ae7b-e0159afa8208.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "resources": { - "core": { - "limit": 5000, - "remaining": 4897, - "reset": 1570478899 - }, - "search": { - "limit": 30, - "remaining": 30, - "reset": 1570478180 - }, - "graphql": { - "limit": 5000, - "remaining": 5000, - "reset": 1570481642 - }, - "integration_manifest": { - "limit": 5000, - "remaining": 5000, - "reset": 1570481642 - } - }, - "rate": { - "limit": 5000, - "remaining": 4897, - "reset": {{now offset='5 seconds' format='unix'}} - } -} \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpiration/__files/rate_limit-f22b1cea-3679-481d-8b95-459b2c47bf98.json b/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpiration/__files/rate_limit-f22b1cea-3679-481d-8b95-459b2c47bf98.json deleted file mode 100644 index d846f8221..000000000 --- a/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpiration/__files/rate_limit-f22b1cea-3679-481d-8b95-459b2c47bf98.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "resources": { - "core": { - "limit": 5000, - "remaining": 4897, - "reset": 1570478899 - }, - "search": { - "limit": 30, - "remaining": 30, - "reset": 1570478180 - }, - "graphql": { - "limit": 5000, - "remaining": 5000, - "reset": 1570481642 - }, - "integration_manifest": { - "limit": 5000, - "remaining": 5000, - "reset": 1570481642 - } - }, - "rate": { - "limit": 5000, - "remaining": 4897, - "reset": {{now offset='5 seconds' format='unix'}} - } -} \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpiration/__files/user-a460fd69-99f3-46c7-aeb1-888c34085d4a.json b/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpiration/__files/user-a460fd69-99f3-46c7-aeb1-888c34085d4a.json deleted file mode 100644 index 41fc9e3d0..000000000 --- a/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpiration/__files/user-a460fd69-99f3-46c7-aeb1-888c34085d4a.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "login": "bitwiseman", - "id": 1958953, - "node_id": "MDQ6VXNlcjE5NTg5NTM=", - "avatar_url": "https://avatars3.githubusercontent.com/u/1958953?v=4", - "gravatar_id": "", - "url": "https://api.github.com/users/bitwiseman", - "html_url": "https://github.com/bitwiseman", - "followers_url": "https://api.github.com/users/bitwiseman/followers", - "following_url": "https://api.github.com/users/bitwiseman/following{/other_user}", - "gists_url": "https://api.github.com/users/bitwiseman/gists{/gist_id}", - "starred_url": "https://api.github.com/users/bitwiseman/starred{/owner}{/repo}", - "subscriptions_url": "https://api.github.com/users/bitwiseman/subscriptions", - "organizations_url": "https://api.github.com/users/bitwiseman/orgs", - "repos_url": "https://api.github.com/users/bitwiseman/repos", - "events_url": "https://api.github.com/users/bitwiseman/events{/privacy}", - "received_events_url": "https://api.github.com/users/bitwiseman/received_events", - "type": "User", - "site_admin": false, - "name": "Liam Newman", - "company": "Cloudbees, Inc.", - "blog": "", - "location": "Seattle, WA, USA", - "email": "bitwiseman@gmail.com", - "hireable": null, - "bio": "https://twitter.com/bitwiseman", - "public_repos": 168, - "public_gists": 4, - "followers": 136, - "following": 9, - "created_at": "2012-07-11T20:38:33Z", - "updated_at": "2019-09-24T19:32:29Z", - "private_gists": 7, - "total_private_repos": 9, - "owned_private_repos": 0, - "disk_usage": 33697, - "collaborators": 0, - "two_factor_authentication": true, - "plan": { - "name": "free", - "space": 976562499, - "collaborators": 0, - "private_repos": 10000 - } -} \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpiration/mappings/rate_limit-2-f22b1c.json b/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpiration/mappings/rate_limit-2-f22b1c.json deleted file mode 100644 index 19fff3635..000000000 --- a/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpiration/mappings/rate_limit-2-f22b1c.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "id": "f22b1cea-3679-481d-8b95-459b2c47bf98", - "name": "rate_limit", - "request": { - "url": "/rate_limit", - "method": "GET" - }, - "response": { - "status": 200, - "bodyFileName": "rate_limit-f22b1cea-3679-481d-8b95-459b2c47bf98.json", - "headers": { - "Date": "{{now timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}", - "Content-Type": "application/json; charset=utf-8", - "Server": "GitHub.com", - "Status": "200 OK", - "X-RateLimit-Limit": "5000", - "X-RateLimit-Remaining": "4897", - "X-RateLimit-Reset": "{{now offset='3 seconds' format='unix'}}", - "Cache-Control": "no-cache", - "X-OAuth-Scopes": "admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete_repo, gist, notifications, repo, user, write:discussion", - "X-Accepted-OAuth-Scopes": "", - "X-GitHub-Media-Type": "unknown, github.v3", - "Access-Control-Expose-Headers": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type", - "Access-Control-Allow-Origin": "*", - "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload", - "X-Frame-Options": "deny", - "X-Content-Type-Options": "nosniff", - "X-XSS-Protection": "1; mode=block", - "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin", - "Content-Security-Policy": "default-src 'none'", - "Vary": "Accept-Encoding", - "X-GitHub-Request-Id": "E39F:3620:2D9D346:369B91A:5D9B9848" - } - }, - "uuid": "f22b1cea-3679-481d-8b95-459b2c47bf98", - "persistent": true, - "scenarioName": "scenario-1-rate_limit", - "requiredScenarioState": "Started", - "newScenarioState": "scenario-1-rate_limit-2", - "insertionIndex": 2 -} \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpiration/mappings/rate_limit-3-a1f82a.json b/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpiration/mappings/rate_limit-3-a1f82a.json deleted file mode 100644 index a2b904158..000000000 --- a/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpiration/mappings/rate_limit-3-a1f82a.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "id": "a1f82a96-500c-4462-ae7b-e0159afa8208", - "name": "rate_limit", - "request": { - "url": "/rate_limit", - "method": "GET" - }, - "response": { - "status": 200, - "bodyFileName": "rate_limit-a1f82a96-500c-4462-ae7b-e0159afa8208.json", - "headers": { - "Date": "{{now timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}", - "Content-Type": "application/json; charset=utf-8", - "Server": "GitHub.com", - "Status": "200 OK", - "X-RateLimit-Limit": "5000", - "X-RateLimit-Remaining": "4897", - "X-RateLimit-Reset": "{{now offset='3 seconds' format='unix'}}", - "Cache-Control": "no-cache", - "X-OAuth-Scopes": "admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete_repo, gist, notifications, repo, user, write:discussion", - "X-Accepted-OAuth-Scopes": "", - "X-GitHub-Media-Type": "unknown, github.v3", - "Access-Control-Expose-Headers": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type", - "Access-Control-Allow-Origin": "*", - "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload", - "X-Frame-Options": "deny", - "X-Content-Type-Options": "nosniff", - "X-XSS-Protection": "1; mode=block", - "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin", - "Content-Security-Policy": "default-src 'none'", - "Vary": "Accept-Encoding", - "X-GitHub-Request-Id": "E39F:3620:2D9D3B3:369BA1D:5D9B984A" - } - }, - "uuid": "a1f82a96-500c-4462-ae7b-e0159afa8208", - "persistent": true, - "scenarioName": "scenario-1-rate_limit", - "requiredScenarioState": "scenario-1-rate_limit-2", - "newScenarioState": "scenario-1-rate_limit-3", - "insertionIndex": 3 -} \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpiration/mappings/rate_limit-5-4e2fc3.json b/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpiration/mappings/rate_limit-5-4e2fc3.json deleted file mode 100644 index 629820ed4..000000000 --- a/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpiration/mappings/rate_limit-5-4e2fc3.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "id": "4e2fc33b-fb25-4dfc-9d56-34f9b4d707be", - "name": "rate_limit", - "request": { - "url": "/rate_limit", - "method": "GET" - }, - "response": { - "status": 200, - "bodyFileName": "rate_limit-4e2fc33b-fb25-4dfc-9d56-34f9b4d707be.json", - "headers": { - "Date": "{{now timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}", - "Content-Type": "application/json; charset=utf-8", - "Server": "GitHub.com", - "Status": "200 OK", - "X-RateLimit-Limit": "5000", - "X-RateLimit-Remaining": "4896", - "X-RateLimit-Reset": "{{now offset='3 seconds' format='unix'}}", - "Cache-Control": "no-cache", - "X-OAuth-Scopes": "admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete_repo, gist, notifications, repo, user, write:discussion", - "X-Accepted-OAuth-Scopes": "", - "X-GitHub-Media-Type": "unknown, github.v3", - "Access-Control-Expose-Headers": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type", - "Access-Control-Allow-Origin": "*", - "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload", - "X-Frame-Options": "deny", - "X-Content-Type-Options": "nosniff", - "X-XSS-Protection": "1; mode=block", - "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin", - "Content-Security-Policy": "default-src 'none'", - "Vary": "Accept-Encoding", - "X-GitHub-Request-Id": "E39F:3620:2D9D3D1:369BAD1:5D9B984C" - } - }, - "uuid": "4e2fc33b-fb25-4dfc-9d56-34f9b4d707be", - "persistent": true, - "scenarioName": "scenario-1-rate_limit", - "requiredScenarioState": "scenario-1-rate_limit-3", - "insertionIndex": 5 -} \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpiration/mappings/user-1-a460fd.json b/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpiration/mappings/user-1-a460fd.json deleted file mode 100644 index 0256fc577..000000000 --- a/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpiration/mappings/user-1-a460fd.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "id": "a460fd69-99f3-46c7-aeb1-888c34085d4a", - "name": "user", - "request": { - "url": "/user", - "method": "GET" - }, - "response": { - "status": 200, - "bodyFileName": "user-a460fd69-99f3-46c7-aeb1-888c34085d4a.json", - "headers": { - "Date": "{{now timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}", - "Content-Type": "application/json; charset=utf-8", - "Server": "GitHub.com", - "Status": "200 OK", - "X-RateLimit-Limit": "5000", - "X-RateLimit-Remaining": "4897", - "X-RateLimit-Reset": "{{now offset='3 seconds' format='unix'}}", - "Cache-Control": "private, max-age=60, s-maxage=60", - "Vary": [ - "Accept, Authorization, Cookie, X-GitHub-OTP", - "Accept-Encoding" - ], - "ETag": "W/\"af0c41afcacb8ceee14b7d896719c3bd\"", - "Last-Modified": "Tue, 24 Sep 2019 19:32:29 GMT", - "X-OAuth-Scopes": "admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete_repo, gist, notifications, repo, user, write:discussion", - "X-Accepted-OAuth-Scopes": "", - "X-GitHub-Media-Type": "unknown, github.v3", - "Access-Control-Expose-Headers": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type", - "Access-Control-Allow-Origin": "*", - "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload", - "X-Frame-Options": "deny", - "X-Content-Type-Options": "nosniff", - "X-XSS-Protection": "1; mode=block", - "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin", - "Content-Security-Policy": "default-src 'none'", - "X-GitHub-Request-Id": "E39F:3620:2D9D266:369B909:5D9B9848" - } - }, - "uuid": "a460fd69-99f3-46c7-aeb1-888c34085d4a", - "persistent": true, - "insertionIndex": 1 -} \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpirationServerFiveMinutesAhead/__files/rate_limit-4e2fc33b-fb25-4dfc-9d56-34f9b4d707be.json b/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpirationServerFiveMinutesAhead/__files/rate_limit-4e2fc33b-fb25-4dfc-9d56-34f9b4d707be.json index 69cf0ad9d..404ebd4de 100644 --- a/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpirationServerFiveMinutesAhead/__files/rate_limit-4e2fc33b-fb25-4dfc-9d56-34f9b4d707be.json +++ b/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpirationServerFiveMinutesAhead/__files/rate_limit-4e2fc33b-fb25-4dfc-9d56-34f9b4d707be.json @@ -3,27 +3,27 @@ "core": { "limit": 5000, "remaining": 4896, - "reset": 1570478899 + "reset": {{now offset='305 seconds' format='unix'}} }, "search": { "limit": 30, "remaining": 30, - "reset": 1570478180 + "reset": {{now offset='305 seconds' format='unix'}} }, "graphql": { "limit": 5000, "remaining": 5000, - "reset": 1570481642 + "reset": {{now offset='305 seconds' format='unix'}} }, "integration_manifest": { "limit": 5000, "remaining": 5000, - "reset": 1570481642 + "reset": {{now offset='305 seconds' format='unix'}} } }, "rate": { "limit": 5000, "remaining": 4896, - "reset": {{now offset='305 seconds' format='unix'}} + "reset": 1570478899 } } \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpirationServerFiveMinutesAhead/__files/rate_limit-a1f82a96-500c-4462-ae7b-e0159afa8208.json b/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpirationServerFiveMinutesAhead/__files/rate_limit-a1f82a96-500c-4462-ae7b-e0159afa8208.json index ef6501911..bacd79c0f 100644 --- a/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpirationServerFiveMinutesAhead/__files/rate_limit-a1f82a96-500c-4462-ae7b-e0159afa8208.json +++ b/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpirationServerFiveMinutesAhead/__files/rate_limit-a1f82a96-500c-4462-ae7b-e0159afa8208.json @@ -3,27 +3,27 @@ "core": { "limit": 5000, "remaining": 4897, - "reset": 1570478899 + "reset": {{now offset='305 seconds' format='unix'}} }, "search": { "limit": 30, "remaining": 30, - "reset": 1570478180 + "reset": {{now offset='305 seconds' format='unix'}} }, "graphql": { "limit": 5000, "remaining": 5000, - "reset": 1570481642 + "reset": {{now offset='305 seconds' format='unix'}} }, "integration_manifest": { "limit": 5000, "remaining": 5000, - "reset": 1570481642 + "reset": {{now offset='305 seconds' format='unix'}} } }, "rate": { "limit": 5000, "remaining": 4897, - "reset": {{now offset='305 seconds' format='unix'}} + "reset": 1570478899 } } \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpirationServerFiveMinutesAhead/__files/rate_limit-f22b1cea-3679-481d-8b95-459b2c47bf98.json b/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpirationServerFiveMinutesAhead/__files/rate_limit-f22b1cea-3679-481d-8b95-459b2c47bf98.json index ef6501911..bacd79c0f 100644 --- a/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpirationServerFiveMinutesAhead/__files/rate_limit-f22b1cea-3679-481d-8b95-459b2c47bf98.json +++ b/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpirationServerFiveMinutesAhead/__files/rate_limit-f22b1cea-3679-481d-8b95-459b2c47bf98.json @@ -3,27 +3,27 @@ "core": { "limit": 5000, "remaining": 4897, - "reset": 1570478899 + "reset": {{now offset='305 seconds' format='unix'}} }, "search": { "limit": 30, "remaining": 30, - "reset": 1570478180 + "reset": {{now offset='305 seconds' format='unix'}} }, "graphql": { "limit": 5000, "remaining": 5000, - "reset": 1570481642 + "reset": {{now offset='305 seconds' format='unix'}} }, "integration_manifest": { "limit": 5000, "remaining": 5000, - "reset": 1570481642 + "reset": {{now offset='305 seconds' format='unix'}} } }, "rate": { "limit": 5000, "remaining": 4897, - "reset": {{now offset='305 seconds' format='unix'}} + "reset": 1570478899 } } \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpirationServerFiveMinutesBehind/__files/rate_limit-4e2fc33b-fb25-4dfc-9d56-34f9b4d707be.json b/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpirationServerFiveMinutesBehind/__files/rate_limit-4e2fc33b-fb25-4dfc-9d56-34f9b4d707be.json index 2d5473a9f..9d326f28a 100644 --- a/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpirationServerFiveMinutesBehind/__files/rate_limit-4e2fc33b-fb25-4dfc-9d56-34f9b4d707be.json +++ b/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpirationServerFiveMinutesBehind/__files/rate_limit-4e2fc33b-fb25-4dfc-9d56-34f9b4d707be.json @@ -3,27 +3,27 @@ "core": { "limit": 5000, "remaining": 4896, - "reset": 1570478899 + "reset": {{now offset='-295 seconds' format='unix'}} }, "search": { "limit": 30, "remaining": 30, - "reset": 1570478180 + "reset": {{now offset='-295 seconds' format='unix'}} }, "graphql": { "limit": 5000, "remaining": 5000, - "reset": 1570481642 + "reset": {{now offset='-295 seconds' format='unix'}} }, "integration_manifest": { "limit": 5000, "remaining": 5000, - "reset": 1570481642 + "reset": {{now offset='-295 seconds' format='unix'}} } }, "rate": { "limit": 5000, "remaining": 4896, - "reset": {{now offset='-295 seconds' format='unix'}} + "reset": 1570478899 } } \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpirationServerFiveMinutesBehind/__files/rate_limit-a1f82a96-500c-4462-ae7b-e0159afa8208.json b/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpirationServerFiveMinutesBehind/__files/rate_limit-a1f82a96-500c-4462-ae7b-e0159afa8208.json index bbb5574bd..c18f00dbb 100644 --- a/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpirationServerFiveMinutesBehind/__files/rate_limit-a1f82a96-500c-4462-ae7b-e0159afa8208.json +++ b/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpirationServerFiveMinutesBehind/__files/rate_limit-a1f82a96-500c-4462-ae7b-e0159afa8208.json @@ -3,27 +3,27 @@ "core": { "limit": 5000, "remaining": 4897, - "reset": 1570478899 + "reset": {{now offset='-295 seconds' format='unix'}} }, "search": { "limit": 30, "remaining": 30, - "reset": 1570478180 + "reset": {{now offset='-295 seconds' format='unix'}} }, "graphql": { "limit": 5000, "remaining": 5000, - "reset": 1570481642 + "reset": {{now offset='-295 seconds' format='unix'}} }, "integration_manifest": { "limit": 5000, "remaining": 5000, - "reset": 1570481642 + "reset": {{now offset='-295 seconds' format='unix'}} } }, "rate": { "limit": 5000, "remaining": 4897, - "reset": {{now offset='-295 seconds' format='unix'}} + "reset": 1570478899 } } \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpirationServerFiveMinutesBehind/__files/rate_limit-f22b1cea-3679-481d-8b95-459b2c47bf98.json b/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpirationServerFiveMinutesBehind/__files/rate_limit-f22b1cea-3679-481d-8b95-459b2c47bf98.json index bbb5574bd..c18f00dbb 100644 --- a/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpirationServerFiveMinutesBehind/__files/rate_limit-f22b1cea-3679-481d-8b95-459b2c47bf98.json +++ b/src/test/resources/org/kohsuke/github/GHRateLimitTest/wiremock/testGitHubRateLimitExpirationServerFiveMinutesBehind/__files/rate_limit-f22b1cea-3679-481d-8b95-459b2c47bf98.json @@ -3,27 +3,27 @@ "core": { "limit": 5000, "remaining": 4897, - "reset": 1570478899 + "reset": {{now offset='-295 seconds' format='unix'}} }, "search": { "limit": 30, "remaining": 30, - "reset": 1570478180 + "reset": {{now offset='-295 seconds' format='unix'}} }, "graphql": { "limit": 5000, "remaining": 5000, - "reset": 1570481642 + "reset": {{now offset='-295 seconds' format='unix'}} }, "integration_manifest": { "limit": 5000, "remaining": 5000, - "reset": 1570481642 + "reset": {{now offset='-295 seconds' format='unix'}} } }, "rate": { "limit": 5000, "remaining": 4897, - "reset": {{now offset='-295 seconds' format='unix'}} + "reset": 1570478899 } } \ No newline at end of file