mirror of
https://github.com/jlengrand/github-api.git
synced 2026-03-10 08:21:21 +00:00
Merge pull request #595 from bitwiseman/issue/rate-limit
Adjust GHRateLimit to system time instead of depending on synchronization
This commit is contained in:
@@ -1,43 +1,385 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.Date;
|
||||
import java.util.Objects;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static java.util.logging.Level.FINEST;
|
||||
|
||||
/**
|
||||
* Rate limit.
|
||||
*
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
@SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD", justification = "JSON API")
|
||||
public class GHRateLimit {
|
||||
|
||||
/**
|
||||
* Remaining calls that can be made.
|
||||
*
|
||||
* @deprecated This value should never have been made public. Use {@link #getRemaining()}
|
||||
*/
|
||||
@Deprecated
|
||||
public int remaining;
|
||||
|
||||
/**
|
||||
* Allotted API call per hour.
|
||||
*
|
||||
* @deprecated This value should never have been made public. Use {@link #getLimit()}
|
||||
*/
|
||||
@Deprecated
|
||||
public int limit;
|
||||
|
||||
/**
|
||||
* The time at which the current rate limit window resets in UTC epoch seconds.
|
||||
* NOTE: that means to
|
||||
*
|
||||
* @deprecated This value should never have been made public. Use {@link #getResetDate()}
|
||||
*/
|
||||
@Deprecated
|
||||
public Date reset;
|
||||
|
||||
|
||||
@Nonnull
|
||||
private final Record core;
|
||||
|
||||
@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
|
||||
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 = core.getRemaining();
|
||||
this.limit = core.getLimit();
|
||||
this.reset = new Date(core.getResetEpochSeconds());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Non-epoch date
|
||||
* 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.
|
||||
*/
|
||||
@SuppressFBWarnings(value = "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR",
|
||||
justification = "The value comes from JSON deserialization")
|
||||
@Nonnull
|
||||
public Date getResetDate() {
|
||||
return new Date(reset.getTime() * 1000);
|
||||
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=" + remaining +
|
||||
", limit=" + limit +
|
||||
return "GHRateLimit {" +
|
||||
"core " + getCore().toString() +
|
||||
"search " + getSearch().toString() +
|
||||
"graphql " + getGraphQL().toString() +
|
||||
"integrationManifest " + getIntegrationManifest().toString() +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
GHRateLimit rateLimit = (GHRateLimit) o;
|
||||
return getCore().equals(rateLimit.getCore()) &&
|
||||
getSearch().equals(rateLimit.getSearch()) &&
|
||||
getGraphQL().equals(rateLimit.getGraphQL()) &&
|
||||
getIntegrationManifest().equals(rateLimit.getIntegrationManifest());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
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());
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
|
||||
import org.apache.commons.codec.Charsets;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import javax.annotation.CheckForNull;
|
||||
import javax.annotation.Nonnull;
|
||||
@@ -315,28 +316,58 @@ public class GitHub {
|
||||
* Gets the current rate limit.
|
||||
*/
|
||||
public GHRateLimit getRateLimit() throws IOException {
|
||||
GHRateLimit rateLimit;
|
||||
try {
|
||||
return 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
|
||||
GHRateLimit r = new GHRateLimit();
|
||||
r.limit = r.remaining = 1000000;
|
||||
long hour = 60L * 60L; // this is madness, storing the date as seconds in a Date object
|
||||
r.reset = new Date(System.currentTimeMillis() / 1000L + hour);
|
||||
return rateLimit = r;
|
||||
// GitHub Enterprise doesn't have the rate limit
|
||||
// return a default rate limit that
|
||||
rateLimit = GHRateLimit.Unknown();
|
||||
}
|
||||
|
||||
return this.rateLimit = rateLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 || shouldReplace(observed, headerRateLimit.getCore())) {
|
||||
headerRateLimit = GHRateLimit.fromHeaderRecord(observed);
|
||||
LOGGER.log(FINE, "Rate limit now: {0}", headerRateLimit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ void updateRateLimit(@Nonnull GHRateLimit observed) {
|
||||
synchronized (headerRateLimitLock) {
|
||||
if (headerRateLimit == null
|
||||
|| headerRateLimit.getResetDate().getTime() < observed.getResetDate().getTime()
|
||||
|| headerRateLimit.remaining > observed.remaining) {
|
||||
headerRateLimit = 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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,12 +393,12 @@ public class GitHub {
|
||||
@Nonnull
|
||||
public GHRateLimit rateLimit() throws IOException {
|
||||
synchronized (headerRateLimitLock) {
|
||||
if (headerRateLimit != null) {
|
||||
if (headerRateLimit != null && !headerRateLimit.isExpired()) {
|
||||
return headerRateLimit;
|
||||
}
|
||||
}
|
||||
GHRateLimit rateLimit = this.rateLimit;
|
||||
if (rateLimit == null || rateLimit.getResetDate().getTime() < System.currentTimeMillis()) {
|
||||
if (rateLimit == null || rateLimit.isExpired()) {
|
||||
rateLimit = getRateLimit();
|
||||
}
|
||||
return rateLimit;
|
||||
|
||||
@@ -4,5 +4,7 @@ package org.kohsuke.github;
|
||||
* @author Kohsuke Kawaguchi
|
||||
*/
|
||||
class JsonRateLimit {
|
||||
GHRateLimit rate;
|
||||
|
||||
GHRateLimit resources;
|
||||
|
||||
}
|
||||
|
||||
@@ -46,7 +46,6 @@ import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -352,54 +351,57 @@ class Requester {
|
||||
}
|
||||
|
||||
private void noteRateLimit(String tailApiUrl) {
|
||||
if ("/rate_limit".equals(tailApiUrl)) {
|
||||
// the rate_limit API is "free"
|
||||
return;
|
||||
}
|
||||
if (tailApiUrl.startsWith("/search")) {
|
||||
// the search API uses a different rate limit
|
||||
return;
|
||||
}
|
||||
String limit = uc.getHeaderField("X-RateLimit-Limit");
|
||||
if (StringUtils.isBlank(limit)) {
|
||||
String limitString = uc.getHeaderField("X-RateLimit-Limit");
|
||||
if (StringUtils.isBlank(limitString)) {
|
||||
// if we are missing a header, return fast
|
||||
return;
|
||||
}
|
||||
String remaining = uc.getHeaderField("X-RateLimit-Remaining");
|
||||
if (StringUtils.isBlank(remaining)) {
|
||||
String remainingString = uc.getHeaderField("X-RateLimit-Remaining");
|
||||
if (StringUtils.isBlank(remainingString)) {
|
||||
// if we are missing a header, return fast
|
||||
return;
|
||||
}
|
||||
String reset = uc.getHeaderField("X-RateLimit-Reset");
|
||||
if (StringUtils.isBlank(reset)) {
|
||||
String resetString = uc.getHeaderField("X-RateLimit-Reset");
|
||||
if (StringUtils.isBlank(resetString)) {
|
||||
// if we are missing a header, return fast
|
||||
return;
|
||||
}
|
||||
GHRateLimit observed = new GHRateLimit();
|
||||
|
||||
int limit, remaining;
|
||||
long reset;
|
||||
try {
|
||||
observed.limit = Integer.parseInt(limit);
|
||||
limit = Integer.parseInt(limitString);
|
||||
} catch (NumberFormatException e) {
|
||||
if (LOGGER.isLoggable(FINEST)) {
|
||||
LOGGER.log(FINEST, "Malformed X-RateLimit-Limit header value " + limit, e);
|
||||
LOGGER.log(FINEST, "Malformed X-RateLimit-Limit header value " + limitString, e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
try {
|
||||
observed.remaining = Integer.parseInt(remaining);
|
||||
|
||||
remaining = Integer.parseInt(remainingString);
|
||||
} catch (NumberFormatException e) {
|
||||
if (LOGGER.isLoggable(FINEST)) {
|
||||
LOGGER.log(FINEST, "Malformed X-RateLimit-Remaining header value " + remaining, e);
|
||||
LOGGER.log(FINEST, "Malformed X-RateLimit-Remaining header value " + remainingString, e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
try {
|
||||
observed.reset = new Date(Long.parseLong(reset)); // this is madness, storing the date as seconds
|
||||
root.updateRateLimit(observed);
|
||||
reset = Long.parseLong(resetString);
|
||||
} catch (NumberFormatException e) {
|
||||
if (LOGGER.isLoggable(FINEST)) {
|
||||
LOGGER.log(FINEST, "Malformed X-RateLimit-Reset header value " + reset, e);
|
||||
LOGGER.log(FINEST, "Malformed X-RateLimit-Reset header value " + resetString, e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
GHRateLimit.Record observed = new GHRateLimit.Record(limit, remaining, reset, uc.getHeaderField("Date"));
|
||||
|
||||
root.updateCoreRateLimit(observed);
|
||||
}
|
||||
|
||||
public String getResponseHeader(String header) {
|
||||
@@ -706,6 +708,9 @@ class Requester {
|
||||
}
|
||||
} else if (readValue instanceof GHObject) {
|
||||
setResponseHeaders((GHObject) readValue);
|
||||
} else if (readValue instanceof JsonRateLimit) {
|
||||
// if we're getting a GHRateLimit it needs the server date
|
||||
((JsonRateLimit)readValue).resources.getCore().recalculateResetDate(uc.getHeaderField("Date"));
|
||||
}
|
||||
return readValue;
|
||||
}
|
||||
|
||||
425
src/test/java/org/kohsuke/github/GHRateLimitTest.java
Normal file
425
src/test/java/org/kohsuke/github/GHRateLimitTest.java
Normal file
@@ -0,0 +1,425 @@
|
||||
package org.kohsuke.github;
|
||||
|
||||
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
|
||||
import com.github.tomakehurst.wiremock.extension.responsetemplating.ResponseTemplateTransformer;
|
||||
import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder;
|
||||
import okhttp3.Cache;
|
||||
import okhttp3.OkHttpClient;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.hamcrest.CoreMatchers;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.kohsuke.github.extras.okhttp3.OkHttpConnector;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
|
||||
|
||||
/**
|
||||
* Test showing the behavior of OkHttpConnector with and without cache.
|
||||
* <p>
|
||||
* Key take aways:
|
||||
*
|
||||
* <ul>
|
||||
* <li>These tests are artificial and intended to highlight the differences
|
||||
* in behavior between scenarios. However, the differences they indicate are stark.</li>
|
||||
* <li>Caching reduces rate limit consumption by at least a factor of two in even the simplest case.</li>
|
||||
* <li>The OkHttp cache is pretty smart and will often connect read and write requests made
|
||||
* on the same client and invalidate caches.</li>
|
||||
* <li>Changes made outside the current client cause the OkHttp cache to return stale data.
|
||||
* This is expected and correct behavior.</li>
|
||||
* <li>"max-age=0" addresses the problem of external changes by revalidating caches for each request.
|
||||
* This produces the same number of requests as OkHttp without caching, but those requests only
|
||||
* count towards the GitHub rate limit if data has changes.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Liam Newman
|
||||
*/
|
||||
public class GHRateLimitTest extends AbstractGitHubWireMockTest {
|
||||
|
||||
public GHRateLimitTest() {
|
||||
useDefaultGitHub = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected WireMockConfiguration getWireMockOptions() {
|
||||
return super.getWireMockOptions()
|
||||
.extensions(ResponseTemplateTransformer.builder()
|
||||
.global(true)
|
||||
.maxCacheEntries(0L)
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGitHubRateLimit() throws Exception {
|
||||
// Customized response that templates the date to keep things working
|
||||
snapshotNotAllowed();
|
||||
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(0));
|
||||
GHRateLimit rateLimit = null;
|
||||
|
||||
Date lastReset = new Date(System.currentTimeMillis() / 1000L);
|
||||
int lastRemaining = 5000;
|
||||
|
||||
// Give this a moment
|
||||
Thread.sleep(1000);
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// /user gets response with rate limit information
|
||||
gitHub = getGitHubBuilder()
|
||||
.withEndpoint(mockGitHub.apiServer().baseUrl()).build();
|
||||
gitHub.getMyself();
|
||||
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(1));
|
||||
|
||||
// Since we already had rate limit info these don't request again
|
||||
rateLimit = gitHub.lastRateLimit();
|
||||
assertThat(rateLimit, notNullValue());
|
||||
assertThat(rateLimit.limit, equalTo(5000));
|
||||
assertThat(rateLimit.getLimit(), equalTo(5000));
|
||||
lastRemaining = rateLimit.getRemaining();
|
||||
assertThat(rateLimit.getResetDate().compareTo(lastReset), greaterThanOrEqualTo(0));
|
||||
lastReset = rateLimit.getResetDate();
|
||||
|
||||
GHRateLimit headerRateLimit = rateLimit;
|
||||
|
||||
// Give this a moment
|
||||
Thread.sleep(1000);
|
||||
|
||||
// ratelimit() uses headerRateLimit if available and headerRateLimit is not expired
|
||||
assertThat(gitHub.rateLimit(), equalTo(headerRateLimit));
|
||||
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(1));
|
||||
|
||||
// Give this a moment
|
||||
Thread.sleep(1000);
|
||||
|
||||
// Always requests new info
|
||||
rateLimit = gitHub.getRateLimit();
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(2));
|
||||
|
||||
assertThat(rateLimit, notNullValue());
|
||||
assertThat(rateLimit.limit, equalTo(5000));
|
||||
assertThat(rateLimit.getLimit(), equalTo(5000));
|
||||
// rate limit request is free
|
||||
assertThat(rateLimit.remaining, equalTo(lastRemaining));
|
||||
assertThat(rateLimit.getRemaining(), equalTo(lastRemaining));
|
||||
assertThat(rateLimit.getResetDate().compareTo(lastReset), greaterThanOrEqualTo(0));
|
||||
|
||||
// Give this a moment
|
||||
Thread.sleep(1000);
|
||||
|
||||
// Always requests new info
|
||||
rateLimit = gitHub.getRateLimit();
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(3));
|
||||
|
||||
assertThat(rateLimit, notNullValue());
|
||||
assertThat(rateLimit.limit, equalTo(5000));
|
||||
assertThat(rateLimit.getLimit(), equalTo(5000));
|
||||
// rate limit request is free
|
||||
assertThat(rateLimit.remaining, equalTo(lastRemaining));
|
||||
assertThat(rateLimit.getRemaining(), equalTo(lastRemaining));
|
||||
assertThat(rateLimit.getResetDate().compareTo(lastReset), greaterThanOrEqualTo(0));
|
||||
|
||||
|
||||
gitHub.getOrganization(GITHUB_API_TEST_ORG);
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(4));
|
||||
|
||||
|
||||
assertThat(gitHub.lastRateLimit(), not(equalTo(headerRateLimit)));
|
||||
rateLimit = gitHub.lastRateLimit();
|
||||
assertThat(rateLimit, notNullValue());
|
||||
assertThat(rateLimit.limit, equalTo(5000));
|
||||
assertThat(rateLimit.getLimit(), equalTo(5000));
|
||||
// Org costs limit to query
|
||||
assertThat(rateLimit.remaining, equalTo(lastRemaining - 1));
|
||||
assertThat(rateLimit.getRemaining(), equalTo(lastRemaining - 1));
|
||||
assertThat(rateLimit.getResetDate().compareTo(lastReset), greaterThanOrEqualTo(0));
|
||||
lastReset = rateLimit.getResetDate();
|
||||
headerRateLimit = rateLimit;
|
||||
|
||||
// ratelimit() should prefer headerRateLimit when it is most recent and not expired
|
||||
assertThat(gitHub.rateLimit(), equalTo(headerRateLimit));
|
||||
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(4));
|
||||
|
||||
// Give this a moment
|
||||
Thread.sleep(2000);
|
||||
|
||||
// Always requests new info
|
||||
rateLimit = gitHub.getRateLimit();
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(5));
|
||||
|
||||
assertThat(rateLimit, notNullValue());
|
||||
assertThat(rateLimit.limit, equalTo(5000));
|
||||
assertThat(rateLimit.getLimit(), equalTo(5000));
|
||||
// Org costs limit to query
|
||||
assertThat(rateLimit.remaining, equalTo(lastRemaining - 1));
|
||||
assertThat(rateLimit.getRemaining(), equalTo(lastRemaining - 1));
|
||||
assertThat(rateLimit.getResetDate().compareTo(lastReset), greaterThanOrEqualTo(0));
|
||||
|
||||
// When getRateLimit() succeeds, headerRateLimit updates as usual as well (if needed)
|
||||
// These are separate instances, but should be equal
|
||||
assertThat(gitHub.rateLimit(), not(sameInstance(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()));
|
||||
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(5));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGitHubEnterpriseDoesNotHaveRateLimit() throws Exception {
|
||||
// Customized response that results in file not found the same as GitHub Enterprise
|
||||
snapshotNotAllowed();
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(0));
|
||||
GHRateLimit rateLimit = null;
|
||||
|
||||
Date lastReset = new Date(System.currentTimeMillis() / 1000L);
|
||||
|
||||
// Give this a moment
|
||||
Thread.sleep(1000);
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// Before any queries, rate limit starts as null but may be requested
|
||||
gitHub = GitHub.connectToEnterprise(mockGitHub.apiServer().baseUrl(), "bogus", "bogus");
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(0));
|
||||
|
||||
assertThat(gitHub.lastRateLimit(), CoreMatchers.nullValue());
|
||||
|
||||
rateLimit = gitHub.rateLimit();
|
||||
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();
|
||||
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(1));
|
||||
|
||||
// last is still null, because it actually means lastHeaderRateLimit
|
||||
assertThat(gitHub.lastRateLimit(), CoreMatchers.nullValue());
|
||||
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(1));
|
||||
|
||||
// Give this a moment
|
||||
Thread.sleep(1000);
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// First call to /user gets response without rate limit information
|
||||
gitHub = GitHub.connectToEnterprise(mockGitHub.apiServer().baseUrl(), "bogus", "bogus");
|
||||
gitHub.getMyself();
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(2));
|
||||
|
||||
assertThat(gitHub.lastRateLimit(), CoreMatchers.nullValue());
|
||||
|
||||
rateLimit = gitHub.rateLimit();
|
||||
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();
|
||||
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(3));
|
||||
|
||||
// Give this a moment
|
||||
Thread.sleep(1000);
|
||||
|
||||
// Always requests new info
|
||||
rateLimit = gitHub.getRateLimit();
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(4));
|
||||
|
||||
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
|
||||
Thread.sleep(1000);
|
||||
|
||||
|
||||
// last is still null, because it actually means lastHeaderRateLimit
|
||||
assertThat(gitHub.lastRateLimit(), CoreMatchers.nullValue());
|
||||
|
||||
// ratelimit() tries not to make additional requests, uses queried rate limit since header not available
|
||||
Thread.sleep(1000);
|
||||
assertThat(gitHub.rateLimit(), sameInstance(rateLimit));
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// Second call to /user gets response with rate limit information
|
||||
gitHub = GitHub.connectToEnterprise(mockGitHub.apiServer().baseUrl(), "bogus", "bogus");
|
||||
gitHub.getMyself();
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(5));
|
||||
|
||||
// Since we already had rate limit info these don't request again
|
||||
rateLimit = gitHub.lastRateLimit();
|
||||
assertThat(rateLimit, notNullValue());
|
||||
assertThat(rateLimit.limit, equalTo(5000));
|
||||
assertThat(rateLimit.getLimit(), equalTo(5000));
|
||||
assertThat(rateLimit.remaining, equalTo(4978));
|
||||
assertThat(rateLimit.getRemaining(), equalTo(4978));
|
||||
assertThat(rateLimit.getResetDate().compareTo(lastReset), greaterThanOrEqualTo(0));
|
||||
lastReset = rateLimit.getResetDate();
|
||||
|
||||
GHRateLimit headerRateLimit = rateLimit;
|
||||
|
||||
// Give this a moment
|
||||
Thread.sleep(1000);
|
||||
|
||||
// ratelimit() uses headerRateLimit if available and headerRateLimit is not expired
|
||||
assertThat(gitHub.rateLimit(), equalTo(headerRateLimit));
|
||||
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(5));
|
||||
|
||||
// Give this a moment
|
||||
Thread.sleep(1000);
|
||||
|
||||
// Always requests new info
|
||||
rateLimit = gitHub.getRateLimit();
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(6));
|
||||
|
||||
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
|
||||
assertThat(gitHub.rateLimit(), equalTo(headerRateLimit));
|
||||
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(6));
|
||||
|
||||
// Wait for the header
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
|
||||
|
||||
// These tests should behave the same, showing server time adjustment working
|
||||
@Test
|
||||
public void testGitHubRateLimitExpirationServerFiveMinutesAhead() throws Exception {
|
||||
executeExpirationTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGitHubRateLimitExpirationServerFiveMinutesBehind() throws Exception {
|
||||
executeExpirationTest();
|
||||
}
|
||||
|
||||
private void executeExpirationTest() throws Exception {
|
||||
// Customized response that templates the date to keep things working
|
||||
snapshotNotAllowed();
|
||||
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(0));
|
||||
GHRateLimit rateLimit = null;
|
||||
GHRateLimit headerRateLimit = null;
|
||||
|
||||
|
||||
// Give this a moment
|
||||
Thread.sleep(1000);
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// /user gets response with rate limit information
|
||||
gitHub = getGitHubBuilder()
|
||||
.withEndpoint(mockGitHub.apiServer().baseUrl()).build();
|
||||
gitHub.getMyself();
|
||||
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(1));
|
||||
|
||||
// Since we already had rate limit info these don't request again
|
||||
headerRateLimit = gitHub.lastRateLimit();
|
||||
rateLimit = gitHub.rateLimit();
|
||||
|
||||
assertThat(rateLimit, notNullValue());
|
||||
assertThat("rateLimit() selects header instance when not expired, does not ask server",
|
||||
rateLimit, sameInstance(headerRateLimit));
|
||||
|
||||
// Nothing changes still valid
|
||||
Thread.sleep(1000);
|
||||
|
||||
assertThat("rateLimit() selects header instance when not expired, does not ask server",
|
||||
gitHub.rateLimit(), sameInstance(headerRateLimit));
|
||||
assertThat("rateLimit() selects header instance when not expired, does not ask server",
|
||||
gitHub.lastRateLimit(), sameInstance(headerRateLimit));
|
||||
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(1));
|
||||
|
||||
// This time, rateLimit() should find an expired record and get a new one.
|
||||
Thread.sleep(3000);
|
||||
|
||||
assertThat("Header instance has expired",
|
||||
gitHub.lastRateLimit().isExpired(), is(true));
|
||||
|
||||
assertThat("rateLimit() will ask server when header instance expires and it has not called getRateLimit() yet",
|
||||
gitHub.rateLimit(), not(sameInstance(rateLimit)));
|
||||
|
||||
assertThat("lastRateLimit() (header instance) is populated as part of internal call to getRateLimit()",
|
||||
gitHub.lastRateLimit(), not(sameInstance(rateLimit)));
|
||||
|
||||
assertThat("After request, rateLimit() selects header instance since it has been refreshed",
|
||||
gitHub.rateLimit(), sameInstance(gitHub.lastRateLimit()));
|
||||
|
||||
headerRateLimit = gitHub.lastRateLimit();
|
||||
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(2));
|
||||
|
||||
|
||||
// This time, rateLimit() should find an expired header record, but a valid returned record
|
||||
Thread.sleep(4000);
|
||||
|
||||
rateLimit = gitHub.rateLimit();
|
||||
|
||||
// Using custom data to have a header instance that expires before the queried instance
|
||||
assertThat("if header instance expires but queried instance is valid, ratelimit() uses it without asking server",
|
||||
gitHub.rateLimit(), not(sameInstance(gitHub.lastRateLimit())));
|
||||
|
||||
assertThat("ratelimit() should almost never return a return a GHRateLimit that is already expired",
|
||||
gitHub.rateLimit().isExpired(), is(false));
|
||||
|
||||
|
||||
assertThat("Header instance hasn't been reloaded",
|
||||
gitHub.lastRateLimit(), sameInstance(headerRateLimit));
|
||||
assertThat("Header instance has expired",
|
||||
gitHub.lastRateLimit().isExpired(), is(true));
|
||||
|
||||
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(2));
|
||||
|
||||
// Finally they both expire and rateLimit() should find both expired and get a new record
|
||||
Thread.sleep(2000);
|
||||
|
||||
headerRateLimit = gitHub.rateLimit();
|
||||
|
||||
assertThat("rateLimit() has asked server for new information",
|
||||
gitHub.rateLimit(), not(sameInstance(rateLimit)));
|
||||
assertThat("rateLimit() has asked server for new information",
|
||||
gitHub.lastRateLimit(), not(sameInstance(rateLimit)));
|
||||
|
||||
|
||||
assertThat("rateLimit() selects header instance when not expired, does not ask server",
|
||||
gitHub.rateLimit(), sameInstance((gitHub.lastRateLimit())));
|
||||
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(3));
|
||||
}
|
||||
|
||||
private static GHRepository getRepository(GitHub gitHub) throws IOException {
|
||||
return gitHub.getOrganization("github-api-test-org").getRepository("github-api");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,8 +6,6 @@ import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
|
||||
/**
|
||||
* Unit test for {@link GitHub}.
|
||||
*/
|
||||
@@ -97,233 +95,6 @@ public class GitHubConnectionTest extends AbstractGitHubWireMockTest {
|
||||
assertEquals("",github.login);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGitHubRateLimit() throws Exception {
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(0));
|
||||
GHRateLimit rateLimit = null;
|
||||
GitHub hub = null;
|
||||
Date lastReset = new Date(System.currentTimeMillis() / 1000L);
|
||||
int lastRemaining = 5000;
|
||||
|
||||
// Give this a moment
|
||||
Thread.sleep(1000);
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// /user gets response with rate limit information
|
||||
hub = getGitHubBuilder()
|
||||
.withEndpoint(mockGitHub.apiServer().baseUrl()).build();
|
||||
hub.getMyself();
|
||||
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(1));
|
||||
|
||||
// Since we already had rate limit info these don't request again
|
||||
rateLimit = hub.lastRateLimit();
|
||||
assertThat(rateLimit, notNullValue());
|
||||
assertThat(rateLimit.limit, equalTo(5000));
|
||||
lastRemaining = rateLimit.remaining;
|
||||
// Because we're gettting this from old mocked info, it will be an older date
|
||||
//assertThat(rateLimit.getResetDate().compareTo(lastReset), equalTo(-1));
|
||||
lastReset = rateLimit.getResetDate();
|
||||
|
||||
GHRateLimit headerRateLimit = rateLimit;
|
||||
|
||||
// Give this a moment
|
||||
Thread.sleep(1000);
|
||||
|
||||
// ratelimit() uses headerRateLimit if available
|
||||
assertThat(hub.rateLimit(), equalTo(headerRateLimit));
|
||||
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(1));
|
||||
|
||||
// Give this a moment
|
||||
Thread.sleep(1000);
|
||||
|
||||
// Always requests new info
|
||||
rateLimit = hub.getRateLimit();
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(2));
|
||||
|
||||
assertThat(rateLimit, notNullValue());
|
||||
assertThat(rateLimit.limit, equalTo(5000));
|
||||
// rate limit request is free
|
||||
assertThat(rateLimit.remaining, equalTo(lastRemaining));
|
||||
assertThat(rateLimit.getResetDate().compareTo(lastReset), equalTo(0));
|
||||
|
||||
// Give this a moment
|
||||
Thread.sleep(1000);
|
||||
|
||||
// Always requests new info
|
||||
rateLimit = hub.getRateLimit();
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(3));
|
||||
|
||||
assertThat(rateLimit, notNullValue());
|
||||
assertThat(rateLimit.limit, equalTo(5000));
|
||||
// rate limit request is free
|
||||
assertThat(rateLimit.remaining, equalTo(lastRemaining));
|
||||
assertThat(rateLimit.getResetDate().compareTo(lastReset), equalTo(0));
|
||||
|
||||
|
||||
hub.getOrganization(GITHUB_API_TEST_ORG);
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(4));
|
||||
|
||||
|
||||
assertThat(hub.lastRateLimit(), not(equalTo(headerRateLimit)));
|
||||
rateLimit = hub.lastRateLimit();
|
||||
assertThat(rateLimit, notNullValue());
|
||||
assertThat(rateLimit.limit, equalTo(5000));
|
||||
// Org costs limit to query
|
||||
assertThat(rateLimit.remaining, equalTo(lastRemaining - 1));
|
||||
assertThat(rateLimit.getResetDate().compareTo(lastReset), equalTo(0));
|
||||
lastReset = rateLimit.getResetDate();
|
||||
headerRateLimit = rateLimit;
|
||||
|
||||
// ratelimit() should prefer headerRateLimit when it is most recent
|
||||
assertThat(hub.rateLimit(), equalTo(headerRateLimit));
|
||||
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(4));
|
||||
|
||||
// Always requests new info
|
||||
rateLimit = hub.getRateLimit();
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(5));
|
||||
|
||||
assertThat(rateLimit, notNullValue());
|
||||
assertThat(rateLimit.limit, equalTo(5000));
|
||||
// Org costs limit to query
|
||||
assertThat(rateLimit.remaining, equalTo(lastRemaining - 1));
|
||||
assertThat(rateLimit.getResetDate().compareTo(lastReset), equalTo(0));
|
||||
|
||||
// ratelimit() should prefer headerRateLimit when getRateLimit() fails
|
||||
// BUG: When getRateLimit() succeeds, it should reset the ratelimit() to the new value
|
||||
// assertThat(hub.rateLimit(), equalTo(rateLimit));
|
||||
// assertThat(hub.rateLimit(), not(equalTo(headerRateLimit)));
|
||||
assertThat(hub.rateLimit(), equalTo(headerRateLimit));
|
||||
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(5));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGitHubEnterpriseDoesNotHaveRateLimit() throws Exception {
|
||||
// Customized response that results in file not found the same as GitHub Enterprise
|
||||
snapshotNotAllowed();
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(0));
|
||||
GHRateLimit rateLimit = null;
|
||||
GitHub hub = null;
|
||||
|
||||
|
||||
Date lastReset = new Date(System.currentTimeMillis() / 1000L);
|
||||
|
||||
// Give this a moment
|
||||
Thread.sleep(1000);
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// Before any queries, rate limit starts as null but may be requested
|
||||
hub = GitHub.connectToEnterprise(mockGitHub.apiServer().baseUrl(), "bogus", "bogus");
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(0));
|
||||
|
||||
assertThat(hub.lastRateLimit(), nullValue());
|
||||
|
||||
rateLimit = hub.rateLimit();
|
||||
assertThat(rateLimit, notNullValue());
|
||||
assertThat(rateLimit.limit, equalTo(1000000));
|
||||
assertThat(rateLimit.remaining, equalTo(1000000));
|
||||
assertThat(rateLimit.getResetDate().compareTo(lastReset), equalTo(1));
|
||||
lastReset = rateLimit.getResetDate();
|
||||
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(1));
|
||||
|
||||
// last is still null, because it actually means lastHeaderRateLimit
|
||||
assertThat(hub.lastRateLimit(), nullValue());
|
||||
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(1));
|
||||
|
||||
// Give this a moment
|
||||
Thread.sleep(1000);
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// First call to /user gets response without rate limit information
|
||||
hub = GitHub.connectToEnterprise(mockGitHub.apiServer().baseUrl(), "bogus", "bogus");
|
||||
hub.getMyself();
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(2));
|
||||
|
||||
assertThat(hub.lastRateLimit(), nullValue());
|
||||
|
||||
rateLimit = hub.rateLimit();
|
||||
assertThat(rateLimit, notNullValue());
|
||||
assertThat(rateLimit.limit, equalTo(1000000));
|
||||
assertThat(rateLimit.remaining, equalTo(1000000));
|
||||
assertThat(rateLimit.getResetDate().compareTo(lastReset), equalTo(1));
|
||||
lastReset = rateLimit.getResetDate();
|
||||
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(3));
|
||||
|
||||
// Give this a moment
|
||||
Thread.sleep(1000);
|
||||
|
||||
// Always requests new info
|
||||
rateLimit = hub.getRateLimit();
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(4));
|
||||
|
||||
assertThat(rateLimit, notNullValue());
|
||||
assertThat(rateLimit.limit, equalTo(1000000));
|
||||
assertThat(rateLimit.remaining, equalTo(1000000));
|
||||
assertThat(rateLimit.getResetDate().compareTo(lastReset), equalTo(1));
|
||||
|
||||
// Give this a moment
|
||||
Thread.sleep(1000);
|
||||
|
||||
|
||||
// last is still null, because it actually means lastHeaderRateLimit
|
||||
assertThat(hub.lastRateLimit(), nullValue());
|
||||
|
||||
// ratelimit() tries not to make additional requests, uses queried rate limit since header not available
|
||||
Thread.sleep(1000);
|
||||
assertThat(hub.rateLimit(), equalTo(rateLimit));
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// Second call to /user gets response with rate limit information
|
||||
hub = GitHub.connectToEnterprise(mockGitHub.apiServer().baseUrl(), "bogus", "bogus");
|
||||
hub.getMyself();
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(5));
|
||||
|
||||
// Since we already had rate limit info these don't request again
|
||||
rateLimit = hub.lastRateLimit();
|
||||
assertThat(rateLimit, notNullValue());
|
||||
assertThat(rateLimit.limit, equalTo(5000));
|
||||
assertThat(rateLimit.remaining, equalTo(4978));
|
||||
// Because we're gettting this from old mocked info, it will be an older date
|
||||
assertThat(rateLimit.getResetDate().compareTo(lastReset), equalTo(-1));
|
||||
lastReset = rateLimit.getResetDate();
|
||||
|
||||
GHRateLimit headerRateLimit = rateLimit;
|
||||
|
||||
// Give this a moment
|
||||
Thread.sleep(1000);
|
||||
|
||||
// ratelimit() uses headerRateLimit if available
|
||||
assertThat(hub.rateLimit(), equalTo(headerRateLimit));
|
||||
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(5));
|
||||
|
||||
// Give this a moment
|
||||
Thread.sleep(1000);
|
||||
|
||||
// Always requests new info
|
||||
rateLimit = hub.getRateLimit();
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(6));
|
||||
|
||||
assertThat(rateLimit, notNullValue());
|
||||
assertThat(rateLimit.limit, equalTo(1000000));
|
||||
assertThat(rateLimit.remaining, equalTo(1000000));
|
||||
assertThat(rateLimit.getResetDate().compareTo(lastReset), equalTo(1));
|
||||
|
||||
// Give this a moment
|
||||
Thread.sleep(1000);
|
||||
|
||||
// ratelimit() should prefer headerRateLimit when getRateLimit fails
|
||||
assertThat(hub.rateLimit(), equalTo(headerRateLimit));
|
||||
|
||||
assertThat(mockGitHub.getRequestCount(), equalTo(6));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGitHubIsApiUrlValid() throws IOException {
|
||||
GitHub hub = GitHub.connectAnonymously();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.squareup.okhttp.Cache;
|
||||
import com.squareup.okhttp.OkHttpClient;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.kohsuke.github.*;
|
||||
|
||||
@@ -185,6 +186,7 @@ public class OkHttpConnectorTest extends AbstractGitHubWireMockTest {
|
||||
assertThat("getHitCount", cache.getHitCount(), is(maxAgeThreeHitCount));
|
||||
}
|
||||
|
||||
@Ignore("ISSUE #597 - Correctly formatted Last-Modified headers cause this test to fail")
|
||||
@Test
|
||||
public void OkHttpConnector_Cache_MaxAgeDefault_Zero() throws Exception {
|
||||
// The responses were recorded from github, but the Date headers
|
||||
|
||||
@@ -9,13 +9,10 @@
|
||||
"status": 404,
|
||||
"body": "{\"message\":\"Not Found\",\"documentation_url\":\"https://developer.github.com/v3\"}",
|
||||
"headers": {
|
||||
"Date": "Mon, 07 Oct 2019 17:05:48 GMT",
|
||||
"Date": "{{now timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}",
|
||||
"Content-Type": "application/json; charset=utf-8",
|
||||
"Server": "GitHub.com",
|
||||
"Status": "404 Not Found",
|
||||
"X-RateLimit-Limit": "5000",
|
||||
"X-RateLimit-Remaining": "4976",
|
||||
"X-RateLimit-Reset": "1570470839",
|
||||
"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": "repo",
|
||||
"X-GitHub-Media-Type": "unknown, github.v3",
|
||||
@@ -9,7 +9,7 @@
|
||||
"status": 200,
|
||||
"bodyFileName": "user-a0bafdae-2f0d-4d0b-966b-f2408c1240bd.json",
|
||||
"headers": {
|
||||
"Date": "Mon, 07 Oct 2019 17:05:48 GMT",
|
||||
"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",
|
||||
@@ -9,13 +9,13 @@
|
||||
"status": 200,
|
||||
"bodyFileName": "user-a0bafdae-2f0d-4d0b-966b-f2408c1240bd.json",
|
||||
"headers": {
|
||||
"Date": "Mon, 07 Oct 2019 17:05:48 GMT",
|
||||
"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": "4978",
|
||||
"X-RateLimit-Reset": "1570470839",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
@@ -3,22 +3,22 @@
|
||||
"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": {
|
||||
@@ -3,22 +3,22 @@
|
||||
"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": {
|
||||
@@ -3,22 +3,22 @@
|
||||
"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": {
|
||||
@@ -9,13 +9,13 @@
|
||||
"status": 200,
|
||||
"bodyFileName": "orgs_github-api-test-org-7ea37b72-8b01-4ed5-a63d-98d32b2faa0f.json",
|
||||
"headers": {
|
||||
"Date": "Mon, 07 Oct 2019 19:55:56 GMT",
|
||||
"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": "1570478899",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
@@ -9,13 +9,13 @@
|
||||
"status": 200,
|
||||
"bodyFileName": "rate_limit-f22b1cea-3679-481d-8b95-459b2c47bf98.json",
|
||||
"headers": {
|
||||
"Date": "Mon, 07 Oct 2019 19:55:54 GMT",
|
||||
"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": "1570478899",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' 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": "",
|
||||
@@ -9,13 +9,13 @@
|
||||
"status": 200,
|
||||
"bodyFileName": "rate_limit-a1f82a96-500c-4462-ae7b-e0159afa8208.json",
|
||||
"headers": {
|
||||
"Date": "Mon, 07 Oct 2019 19:55:55 GMT",
|
||||
"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": "1570478899",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' 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": "",
|
||||
@@ -9,13 +9,13 @@
|
||||
"status": 200,
|
||||
"bodyFileName": "rate_limit-4e2fc33b-fb25-4dfc-9d56-34f9b4d707be.json",
|
||||
"headers": {
|
||||
"Date": "Mon, 07 Oct 2019 19:55:56 GMT",
|
||||
"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": "1570478899",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' 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": "",
|
||||
@@ -9,13 +9,13 @@
|
||||
"status": 200,
|
||||
"bodyFileName": "user-a460fd69-99f3-46c7-aeb1-888c34085d4a.json",
|
||||
"headers": {
|
||||
"Date": "Mon, 07 Oct 2019 19:55:52 GMT",
|
||||
"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": "1570478899",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"resources": {
|
||||
"core": {
|
||||
"limit": 5000,
|
||||
"remaining": 4896,
|
||||
"reset": {{now offset='305 seconds' format='unix'}}
|
||||
},
|
||||
"search": {
|
||||
"limit": 30,
|
||||
"remaining": 30,
|
||||
"reset": {{now offset='305 seconds' format='unix'}}
|
||||
},
|
||||
"graphql": {
|
||||
"limit": 5000,
|
||||
"remaining": 5000,
|
||||
"reset": {{now offset='305 seconds' format='unix'}}
|
||||
},
|
||||
"integration_manifest": {
|
||||
"limit": 5000,
|
||||
"remaining": 5000,
|
||||
"reset": {{now offset='305 seconds' format='unix'}}
|
||||
}
|
||||
},
|
||||
"rate": {
|
||||
"limit": 5000,
|
||||
"remaining": 4896,
|
||||
"reset": 1570478899
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"resources": {
|
||||
"core": {
|
||||
"limit": 5000,
|
||||
"remaining": 4897,
|
||||
"reset": {{now offset='305 seconds' format='unix'}}
|
||||
},
|
||||
"search": {
|
||||
"limit": 30,
|
||||
"remaining": 30,
|
||||
"reset": {{now offset='305 seconds' format='unix'}}
|
||||
},
|
||||
"graphql": {
|
||||
"limit": 5000,
|
||||
"remaining": 5000,
|
||||
"reset": {{now offset='305 seconds' format='unix'}}
|
||||
},
|
||||
"integration_manifest": {
|
||||
"limit": 5000,
|
||||
"remaining": 5000,
|
||||
"reset": {{now offset='305 seconds' format='unix'}}
|
||||
}
|
||||
},
|
||||
"rate": {
|
||||
"limit": 5000,
|
||||
"remaining": 4897,
|
||||
"reset": 1570478899
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"resources": {
|
||||
"core": {
|
||||
"limit": 5000,
|
||||
"remaining": 4897,
|
||||
"reset": {{now offset='305 seconds' format='unix'}}
|
||||
},
|
||||
"search": {
|
||||
"limit": 30,
|
||||
"remaining": 30,
|
||||
"reset": {{now offset='305 seconds' format='unix'}}
|
||||
},
|
||||
"graphql": {
|
||||
"limit": 5000,
|
||||
"remaining": 5000,
|
||||
"reset": {{now offset='305 seconds' format='unix'}}
|
||||
},
|
||||
"integration_manifest": {
|
||||
"limit": 5000,
|
||||
"remaining": 5000,
|
||||
"reset": {{now offset='305 seconds' format='unix'}}
|
||||
}
|
||||
},
|
||||
"rate": {
|
||||
"limit": 5000,
|
||||
"remaining": 4897,
|
||||
"reset": 1570478899
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"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 offset='5 minutes' 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='303 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
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"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 offset='5 minutes' 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='303 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
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"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 offset='5 minutes' 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='303 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
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"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 offset='5 minutes' 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='303 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
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"resources": {
|
||||
"core": {
|
||||
"limit": 5000,
|
||||
"remaining": 4896,
|
||||
"reset": {{now offset='-295 seconds' format='unix'}}
|
||||
},
|
||||
"search": {
|
||||
"limit": 30,
|
||||
"remaining": 30,
|
||||
"reset": {{now offset='-295 seconds' format='unix'}}
|
||||
},
|
||||
"graphql": {
|
||||
"limit": 5000,
|
||||
"remaining": 5000,
|
||||
"reset": {{now offset='-295 seconds' format='unix'}}
|
||||
},
|
||||
"integration_manifest": {
|
||||
"limit": 5000,
|
||||
"remaining": 5000,
|
||||
"reset": {{now offset='-295 seconds' format='unix'}}
|
||||
}
|
||||
},
|
||||
"rate": {
|
||||
"limit": 5000,
|
||||
"remaining": 4896,
|
||||
"reset": 1570478899
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"resources": {
|
||||
"core": {
|
||||
"limit": 5000,
|
||||
"remaining": 4897,
|
||||
"reset": {{now offset='-295 seconds' format='unix'}}
|
||||
},
|
||||
"search": {
|
||||
"limit": 30,
|
||||
"remaining": 30,
|
||||
"reset": {{now offset='-295 seconds' format='unix'}}
|
||||
},
|
||||
"graphql": {
|
||||
"limit": 5000,
|
||||
"remaining": 5000,
|
||||
"reset": {{now offset='-295 seconds' format='unix'}}
|
||||
},
|
||||
"integration_manifest": {
|
||||
"limit": 5000,
|
||||
"remaining": 5000,
|
||||
"reset": {{now offset='-295 seconds' format='unix'}}
|
||||
}
|
||||
},
|
||||
"rate": {
|
||||
"limit": 5000,
|
||||
"remaining": 4897,
|
||||
"reset": 1570478899
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"resources": {
|
||||
"core": {
|
||||
"limit": 5000,
|
||||
"remaining": 4897,
|
||||
"reset": {{now offset='-295 seconds' format='unix'}}
|
||||
},
|
||||
"search": {
|
||||
"limit": 30,
|
||||
"remaining": 30,
|
||||
"reset": {{now offset='-295 seconds' format='unix'}}
|
||||
},
|
||||
"graphql": {
|
||||
"limit": 5000,
|
||||
"remaining": 5000,
|
||||
"reset": {{now offset='-295 seconds' format='unix'}}
|
||||
},
|
||||
"integration_manifest": {
|
||||
"limit": 5000,
|
||||
"remaining": 5000,
|
||||
"reset": {{now offset='-295 seconds' format='unix'}}
|
||||
}
|
||||
},
|
||||
"rate": {
|
||||
"limit": 5000,
|
||||
"remaining": 4897,
|
||||
"reset": 1570478899
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"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 offset='-5 minutes' 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='-297 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
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"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 offset='-5 minutes' 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='-297 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
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"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 offset='-5 minutes' 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='-297 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
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"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 offset='-5 minutes' 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='-297 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
|
||||
}
|
||||
@@ -24,6 +24,6 @@
|
||||
"rate": {
|
||||
"limit": 5000,
|
||||
"remaining": 4717,
|
||||
"reset": 1569866107
|
||||
"reset": {{now offset='1 hours' format='unix'}}
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,6 @@
|
||||
"rate": {
|
||||
"limit": 5000,
|
||||
"remaining": 4970,
|
||||
"reset": 1569875630
|
||||
"reset": {{now offset='1 hours' format='unix'}}
|
||||
}
|
||||
}
|
||||
@@ -9,13 +9,13 @@
|
||||
"status": 200,
|
||||
"bodyFileName": "orgs_github-api-test-org-ec2931f3-a8cd-4482-a866-aca52276d270.json",
|
||||
"headers": {
|
||||
"Date": "{{now}}",
|
||||
"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": "4969",
|
||||
"X-RateLimit-Reset": "1569875630",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
"status": 200,
|
||||
"bodyFileName": "rate_limit-36588a64-cb68-4ea5-8995-c2cdced6b84a.json",
|
||||
"headers": {
|
||||
"Date": "{{now}}",
|
||||
"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": "4970",
|
||||
"X-RateLimit-Reset": "1569875630",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "no-cache",
|
||||
"X-OAuth-Scopes": "gist, notifications, read:org, read:public_key, read:repo_hook, repo",
|
||||
"X-Accepted-OAuth-Scopes": "",
|
||||
|
||||
@@ -9,20 +9,20 @@
|
||||
"status": 200,
|
||||
"bodyFileName": "repos_github-api-test-org_github-api-5432b23c-70f2-4ecf-a380-a232afeef015.json",
|
||||
"headers": {
|
||||
"Date": "{{now}}",
|
||||
"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": "4966",
|
||||
"X-RateLimit-Reset": "1569875630",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
"Accept-Encoding"
|
||||
],
|
||||
"ETag": "W/\"4f508593b64df214fee8f6ab42df633c\"",
|
||||
"Last-Modified": "{{now offset='-1 seconds'}}",
|
||||
"Last-Modified": "{{now offset='-1 seconds' timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}",
|
||||
"X-OAuth-Scopes": "gist, notifications, read:org, read:public_key, read:repo_hook, repo",
|
||||
"X-Accepted-OAuth-Scopes": "repo",
|
||||
"X-GitHub-Media-Type": "github.v3; format=json",
|
||||
|
||||
@@ -13,19 +13,19 @@
|
||||
"response": {
|
||||
"status": 304,
|
||||
"headers": {
|
||||
"Date": "{{now}}",
|
||||
"Date": "{{now timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}",
|
||||
"Server": "GitHub.com",
|
||||
"Status": "304 Not Modified",
|
||||
"X-RateLimit-Limit": "5000",
|
||||
"X-RateLimit-Remaining": "4966",
|
||||
"X-RateLimit-Reset": "1569875630",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
"Accept-Encoding"
|
||||
],
|
||||
"ETag": "\"4f508593b64df214fee8f6ab42df633c\"",
|
||||
"Last-Modified": "{{now offset='-1 seconds'}}",
|
||||
"Last-Modified": "{{now offset='-1 seconds' timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}",
|
||||
"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",
|
||||
|
||||
@@ -13,19 +13,19 @@
|
||||
"response": {
|
||||
"status": 304,
|
||||
"headers": {
|
||||
"Date": "{{now}}",
|
||||
"Date": "{{now timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}",
|
||||
"Server": "GitHub.com",
|
||||
"Status": "304 Not Modified",
|
||||
"X-RateLimit-Limit": "5000",
|
||||
"X-RateLimit-Remaining": "4966",
|
||||
"X-RateLimit-Reset": "1569875630",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
"Accept-Encoding"
|
||||
],
|
||||
"ETag": "\"4f508593b64df214fee8f6ab42df633c\"",
|
||||
"Last-Modified": "{{now offset='-2 seconds'}}",
|
||||
"Last-Modified": "{{now offset='-2 seconds' timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}",
|
||||
"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",
|
||||
|
||||
@@ -13,19 +13,19 @@
|
||||
"response": {
|
||||
"status": 304,
|
||||
"headers": {
|
||||
"Date": "{{now}}",
|
||||
"Date": "{{now timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}",
|
||||
"Server": "GitHub.com",
|
||||
"Status": "304 Not Modified",
|
||||
"X-RateLimit-Limit": "5000",
|
||||
"X-RateLimit-Remaining": "4966",
|
||||
"X-RateLimit-Reset": "1569875630",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
"Accept-Encoding"
|
||||
],
|
||||
"ETag": "\"4f508593b64df214fee8f6ab42df633c\"",
|
||||
"Last-Modified": "{{now offset='-3 seconds'}}",
|
||||
"Last-Modified": "{{now offset='-3 seconds' timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}",
|
||||
"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",
|
||||
|
||||
@@ -14,20 +14,20 @@
|
||||
"status": 200,
|
||||
"bodyFileName": "repos_github-api-test-org_github-api-7e396e4c-c5eb-4bc0-a5cd-3d9f75fac0f0.json",
|
||||
"headers": {
|
||||
"Date": "{{now}}",
|
||||
"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": "4963",
|
||||
"X-RateLimit-Reset": "1569875630",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
"Accept-Encoding"
|
||||
],
|
||||
"ETag": "W/\"31f73a7ecc35bbecec125851ce166af4\"",
|
||||
"Last-Modified": "{{now offset='-7 seconds'}}",
|
||||
"Last-Modified": "{{now offset='-7 seconds' timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}",
|
||||
"X-OAuth-Scopes": "gist, notifications, read:org, read:public_key, read:repo_hook, repo",
|
||||
"X-Accepted-OAuth-Scopes": "repo",
|
||||
"X-GitHub-Media-Type": "github.v3; format=json",
|
||||
|
||||
@@ -13,19 +13,19 @@
|
||||
"response": {
|
||||
"status": 304,
|
||||
"headers": {
|
||||
"Date": "{{now}}",
|
||||
"Date": "{{now timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}",
|
||||
"Server": "GitHub.com",
|
||||
"Status": "304 Not Modified",
|
||||
"X-RateLimit-Limit": "5000",
|
||||
"X-RateLimit-Remaining": "4963",
|
||||
"X-RateLimit-Reset": "1569875630",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
"Accept-Encoding"
|
||||
],
|
||||
"ETag": "\"31f73a7ecc35bbecec125851ce166af4\"",
|
||||
"Last-Modified": "{{now offset='-10 seconds'}}",
|
||||
"Last-Modified": "{{now offset='-10 seconds' timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}",
|
||||
"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",
|
||||
|
||||
@@ -13,19 +13,19 @@
|
||||
"response": {
|
||||
"status": 304,
|
||||
"headers": {
|
||||
"Date": "{{now}}",
|
||||
"Date": "{{now timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}",
|
||||
"Server": "GitHub.com",
|
||||
"Status": "304 Not Modified",
|
||||
"X-RateLimit-Limit": "5000",
|
||||
"X-RateLimit-Remaining": "4963",
|
||||
"X-RateLimit-Reset": "1569875630",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
"Accept-Encoding"
|
||||
],
|
||||
"ETag": "\"31f73a7ecc35bbecec125851ce166af4\"",
|
||||
"Last-Modified": "{{now offset='-15 seconds'}}",
|
||||
"Last-Modified": "{{now offset='-15 seconds' timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}",
|
||||
"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",
|
||||
|
||||
@@ -13,19 +13,19 @@
|
||||
"response": {
|
||||
"status": 304,
|
||||
"headers": {
|
||||
"Date": "{{now}}",
|
||||
"Date": "{{now timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}",
|
||||
"Server": "GitHub.com",
|
||||
"Status": "304 Not Modified",
|
||||
"X-RateLimit-Limit": "5000",
|
||||
"X-RateLimit-Remaining": "4963",
|
||||
"X-RateLimit-Reset": "1569875630",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
"Accept-Encoding"
|
||||
],
|
||||
"ETag": "\"31f73a7ecc35bbecec125851ce166af4\"",
|
||||
"Last-Modified": "{{now offset='-20 seconds'}}",
|
||||
"Last-Modified": "{{now offset='-20 seconds' timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}",
|
||||
"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",
|
||||
|
||||
@@ -9,20 +9,20 @@
|
||||
"status": 200,
|
||||
"bodyFileName": "repos_github-api-test-org_github-api-b99f84bd-4eaa-4aeb-8f1c-ba64e617d15f.json",
|
||||
"headers": {
|
||||
"Date": "{{now}}",
|
||||
"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": "4968",
|
||||
"X-RateLimit-Reset": "1569875630",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
"Accept-Encoding"
|
||||
],
|
||||
"ETag": "W/\"295ae3430c604f3d10b6eb145fe511b5\"",
|
||||
"Last-Modified": "{{now offset='-1 seconds'}}",
|
||||
"Last-Modified": "{{now offset='-1 seconds' timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}",
|
||||
"X-OAuth-Scopes": "gist, notifications, read:org, read:public_key, read:repo_hook, repo",
|
||||
"X-Accepted-OAuth-Scopes": "repo",
|
||||
"X-GitHub-Media-Type": "github.v3; format=json",
|
||||
|
||||
@@ -13,19 +13,19 @@
|
||||
"response": {
|
||||
"status": 304,
|
||||
"headers": {
|
||||
"Date": "{{now}}",
|
||||
"Date": "{{now timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}",
|
||||
"Server": "GitHub.com",
|
||||
"Status": "304 Not Modified",
|
||||
"X-RateLimit-Limit": "5000",
|
||||
"X-RateLimit-Remaining": "4968",
|
||||
"X-RateLimit-Reset": "1569875630",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
"Accept-Encoding"
|
||||
],
|
||||
"ETag": "\"295ae3430c604f3d10b6eb145fe511b5\"",
|
||||
"Last-Modified": "{{now offset='-1 seconds'}}",
|
||||
"Last-Modified": "{{now offset='-1 seconds' timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}",
|
||||
"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",
|
||||
|
||||
@@ -13,19 +13,19 @@
|
||||
"response": {
|
||||
"status": 304,
|
||||
"headers": {
|
||||
"Date": "{{now}}",
|
||||
"Date": "{{now timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}",
|
||||
"Server": "GitHub.com",
|
||||
"Status": "304 Not Modified",
|
||||
"X-RateLimit-Limit": "5000",
|
||||
"X-RateLimit-Remaining": "4968",
|
||||
"X-RateLimit-Reset": "1569875630",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
"Accept-Encoding"
|
||||
],
|
||||
"ETag": "\"295ae3430c604f3d10b6eb145fe511b5\"",
|
||||
"Last-Modified": "{{now offset='-2 seconds'}}",
|
||||
"Last-Modified": "{{now offset='-2 seconds' timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}",
|
||||
"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",
|
||||
|
||||
@@ -13,19 +13,19 @@
|
||||
"response": {
|
||||
"status": 304,
|
||||
"headers": {
|
||||
"Date": "{{now}}",
|
||||
"Date": "{{now timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}",
|
||||
"Server": "GitHub.com",
|
||||
"Status": "304 Not Modified",
|
||||
"X-RateLimit-Limit": "5000",
|
||||
"X-RateLimit-Remaining": "4968",
|
||||
"X-RateLimit-Reset": "1569875630",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
"Accept-Encoding"
|
||||
],
|
||||
"ETag": "\"295ae3430c604f3d10b6eb145fe511b5\"",
|
||||
"Last-Modified": "{{now offset='-3 seconds'}}",
|
||||
"Last-Modified": "{{now offset='-3 seconds' timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}",
|
||||
"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",
|
||||
|
||||
@@ -8,19 +8,19 @@
|
||||
"response": {
|
||||
"status": 304,
|
||||
"headers": {
|
||||
"Date": "{{now}}",
|
||||
"Date": "{{now timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}",
|
||||
"Server": "GitHub.com",
|
||||
"Status": "304 Not Modified",
|
||||
"X-RateLimit-Limit": "5000",
|
||||
"X-RateLimit-Remaining": "4968",
|
||||
"X-RateLimit-Reset": "1569875630",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
"Accept-Encoding"
|
||||
],
|
||||
"ETag": "\"295ae3430c604f3d10b6eb145fe511b5\"",
|
||||
"Last-Modified": "{{now offset='-7 seconds'}}",
|
||||
"Last-Modified": "{{now offset='-7 seconds' timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}",
|
||||
"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",
|
||||
|
||||
@@ -16,13 +16,13 @@
|
||||
"status": 200,
|
||||
"bodyFileName": "repos_github-api-test-org_github-api-0db05723-d8ab-412d-bcaf-fa416eb44138.json",
|
||||
"headers": {
|
||||
"Date": "{{now}}",
|
||||
"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": "4967",
|
||||
"X-RateLimit-Reset": "1569875630",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
"status": 200,
|
||||
"bodyFileName": "user-5dbb2b95-e55b-4185-b143-ec3f21495fa6.json",
|
||||
"headers": {
|
||||
"Date": "{{now}}",
|
||||
"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": "4970",
|
||||
"X-RateLimit-Reset": "1569875630",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
"rate": {
|
||||
"limit": 5000,
|
||||
"remaining": 4984,
|
||||
"reset": 1569872730
|
||||
"reset": {{now offset='1 hours' format='unix'}}
|
||||
}
|
||||
}
|
||||
@@ -9,13 +9,13 @@
|
||||
"status": 200,
|
||||
"bodyFileName": "orgs_github-api-test-org-1d3815b7-1441-4a5d-a4eb-ffa13c700503.json",
|
||||
"headers": {
|
||||
"Date": "{{now}}",
|
||||
"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": "4983",
|
||||
"X-RateLimit-Reset": "1569872730",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
"status": 200,
|
||||
"bodyFileName": "rate_limit-b23929e7-7216-403a-b1c4-1b0c2ecf6f85.json",
|
||||
"headers": {
|
||||
"Date": "{{now}}",
|
||||
"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": "4984",
|
||||
"X-RateLimit-Reset": "1569872730",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "no-cache",
|
||||
"X-OAuth-Scopes": "gist, notifications, read:org, read:public_key, read:repo_hook, repo",
|
||||
"X-Accepted-OAuth-Scopes": "",
|
||||
|
||||
@@ -9,20 +9,20 @@
|
||||
"status": 200,
|
||||
"bodyFileName": "repos_github-api-test-org_github-api-ec57e178-8204-439b-b45a-58c773fa46f6.json",
|
||||
"headers": {
|
||||
"Date": "{{now}}",
|
||||
"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": "4982",
|
||||
"X-RateLimit-Reset": "1569872730",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
"Accept-Encoding"
|
||||
],
|
||||
"ETag": "W/\"ef30773e1dfdb07ba4ea64143df970ab\"",
|
||||
"Last-Modified": "{{now offset='-20 seconds'}}",
|
||||
"Last-Modified": "{{now offset='-20 seconds' timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}",
|
||||
"X-OAuth-Scopes": "gist, notifications, read:org, read:public_key, read:repo_hook, repo",
|
||||
"X-Accepted-OAuth-Scopes": "repo",
|
||||
"X-GitHub-Media-Type": "github.v3; format=json",
|
||||
|
||||
@@ -16,13 +16,13 @@
|
||||
"status": 200,
|
||||
"bodyFileName": "repos_github-api-test-org_github-api-82db6373-85d8-4fc9-97c7-b98612c52402.json",
|
||||
"headers": {
|
||||
"Date": "{{now}}",
|
||||
"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": "4981",
|
||||
"X-RateLimit-Reset": "1569872730",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
|
||||
@@ -9,20 +9,20 @@
|
||||
"status": 200,
|
||||
"bodyFileName": "repos_github-api-test-org_github-api-02d53c37-9838-422a-9184-a08ef1487126.json",
|
||||
"headers": {
|
||||
"Date": "{{now}}",
|
||||
"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": "4980",
|
||||
"X-RateLimit-Reset": "1569872730",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
"Accept-Encoding"
|
||||
],
|
||||
"ETag": "W/\"ff0623de72a672b583e0f4473a5bb57c\"",
|
||||
"Last-Modified": "{{now offset='-20 seconds'}}",
|
||||
"Last-Modified": "{{now offset='-20 seconds' timezone='GMT' format='EEE, dd MMM yyyy HH:mm:ss z'}}",
|
||||
"X-OAuth-Scopes": "gist, notifications, read:org, read:public_key, read:repo_hook, repo",
|
||||
"X-Accepted-OAuth-Scopes": "repo",
|
||||
"X-GitHub-Media-Type": "github.v3; format=json",
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
"status": 200,
|
||||
"bodyFileName": "user-d958863f-a1fb-4a46-bc43-aeccd3eef451.json",
|
||||
"headers": {
|
||||
"Date": "{{now}}",
|
||||
"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": "4984",
|
||||
"X-RateLimit-Reset": "1569872730",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
"rate": {
|
||||
"limit": 5000,
|
||||
"remaining": 4995,
|
||||
"reset": 1569867392
|
||||
"reset": {{now offset='1 hours' format='unix'}}
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
"Status": "200 OK",
|
||||
"X-RateLimit-Limit": "5000",
|
||||
"X-RateLimit-Remaining": "4994",
|
||||
"X-RateLimit-Reset": "1569867392",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"Status": "200 OK",
|
||||
"X-RateLimit-Limit": "5000",
|
||||
"X-RateLimit-Remaining": "4995",
|
||||
"X-RateLimit-Reset": "1569867392",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "no-cache",
|
||||
"X-OAuth-Scopes": "gist, notifications, read:org, read:public_key, read:repo_hook, repo",
|
||||
"X-Accepted-OAuth-Scopes": "",
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"Status": "200 OK",
|
||||
"X-RateLimit-Limit": "5000",
|
||||
"X-RateLimit-Remaining": "4987",
|
||||
"X-RateLimit-Reset": "1569867392",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"Status": "200 OK",
|
||||
"X-RateLimit-Limit": "5000",
|
||||
"X-RateLimit-Remaining": "4986",
|
||||
"X-RateLimit-Reset": "1569867392",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"Status": "200 OK",
|
||||
"X-RateLimit-Limit": "5000",
|
||||
"X-RateLimit-Remaining": "4985",
|
||||
"X-RateLimit-Reset": "1569867392",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"Status": "200 OK",
|
||||
"X-RateLimit-Limit": "5000",
|
||||
"X-RateLimit-Remaining": "4984",
|
||||
"X-RateLimit-Reset": "1569867392",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"Status": "200 OK",
|
||||
"X-RateLimit-Limit": "5000",
|
||||
"X-RateLimit-Remaining": "4981",
|
||||
"X-RateLimit-Reset": "1569867392",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"Status": "200 OK",
|
||||
"X-RateLimit-Limit": "5000",
|
||||
"X-RateLimit-Remaining": "4980",
|
||||
"X-RateLimit-Reset": "1569867392",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"Status": "200 OK",
|
||||
"X-RateLimit-Limit": "5000",
|
||||
"X-RateLimit-Remaining": "4979",
|
||||
"X-RateLimit-Reset": "1569867392",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"Status": "200 OK",
|
||||
"X-RateLimit-Limit": "5000",
|
||||
"X-RateLimit-Remaining": "4978",
|
||||
"X-RateLimit-Reset": "1569867392",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"Status": "200 OK",
|
||||
"X-RateLimit-Limit": "5000",
|
||||
"X-RateLimit-Remaining": "4993",
|
||||
"X-RateLimit-Reset": "1569867392",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"Status": "200 OK",
|
||||
"X-RateLimit-Limit": "5000",
|
||||
"X-RateLimit-Remaining": "4992",
|
||||
"X-RateLimit-Reset": "1569867392",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"Status": "200 OK",
|
||||
"X-RateLimit-Limit": "5000",
|
||||
"X-RateLimit-Remaining": "4991",
|
||||
"X-RateLimit-Reset": "1569867392",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"Status": "200 OK",
|
||||
"X-RateLimit-Limit": "5000",
|
||||
"X-RateLimit-Remaining": "4990",
|
||||
"X-RateLimit-Reset": "1569867392",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"Status": "200 OK",
|
||||
"X-RateLimit-Limit": "5000",
|
||||
"X-RateLimit-Remaining": "4989",
|
||||
"X-RateLimit-Reset": "1569867392",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
"Status": "200 OK",
|
||||
"X-RateLimit-Limit": "5000",
|
||||
"X-RateLimit-Remaining": "4988",
|
||||
"X-RateLimit-Reset": "1569867392",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"Status": "200 OK",
|
||||
"X-RateLimit-Limit": "5000",
|
||||
"X-RateLimit-Remaining": "4995",
|
||||
"X-RateLimit-Reset": "1569867392",
|
||||
"X-RateLimit-Reset": "{{now offset='1 hours' format='unix'}}",
|
||||
"Cache-Control": "private, max-age=60, s-maxage=60",
|
||||
"Vary": [
|
||||
"Accept, Authorization, Cookie, X-GitHub-OTP",
|
||||
|
||||
Reference in New Issue
Block a user