Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Use github-api v1.115 #314

Merged
merged 1 commit into from
Jul 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>github-api</artifactId>
<version>1.111.4</version>
<version>1.115</version>
</dependency>
<!-- TODO: after upgrading jenkins.version >= 2.171, migrate dependency -->
<dependency>
Expand All @@ -57,7 +57,7 @@
<dependency>
<groupId>com.coravy.hudson.plugins.github</groupId>
<artifactId>github</artifactId>
<version>1.29.3</version>
<version>1.31.0</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package org.jenkinsci.plugins.github_branch_source;

import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.ScenarioMappingBuilder;
import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder;
import com.github.tomakehurst.wiremock.stubbing.Scenario;
import hudson.util.LogTaskListener;
import hudson.util.RingBufferLogHandler;
Expand Down Expand Up @@ -46,6 +48,10 @@ private long countOfOutputLinesContaining(String substring) {
return countOfOutputLines(m -> m.contains(substring));
}

public static int getRequestCount(WireMockServer server) {
return server.countRequestsMatching(RequestPatternBuilder.allRequests().build()).getCount();
}

private class RateLimit {
final int remaining;
final int limit;
Expand Down Expand Up @@ -136,6 +142,7 @@ public void ThrottleOnOverTestWithQuota() throws Exception {
}

assertEquals(0, countOfOutputLinesContaining("Sleeping"));
assertEquals(100, getRequestCount(githubApi));
}

/**
Expand All @@ -158,6 +165,7 @@ public void ThrottleOnNormalizeTestWithQuota() throws Exception {
}

assertEquals(0, countOfOutputLinesContaining("Sleeping"));
assertEquals(100, getRequestCount(githubApi));
}

/**
Expand All @@ -180,7 +188,7 @@ public void ThrottleOnOverTest() throws Exception {
}

// finally, stop throttling by restoring quota
scenarios.add(new RateLimit(limit, limit, soon));
scenarios.add(new RateLimit(limit, limit, new Date(soon.getTime() + 2000)));
setupStubs(scenarios);

// check rate limit to hit the first 11 scenarios because the throttle (add more here)
Expand All @@ -192,19 +200,23 @@ public void ThrottleOnOverTest() throws Exception {
//should be no output
assertEquals(0, countOfOutputLines(m -> m.matches("[sS]leeping")));

assertEquals(11, getRequestCount(githubApi));

// check rate limit to hit the next 10 scenarios
ApiRateLimitChecker.ThrottleOnOver.checkApiRateLimit(listener, github);

//output for all the throttled scenarios. Sleeps normally on the first and then the `notify` hits the next 9
assertEquals(1, countOfOutputLinesContaining("Sleeping for"));
assertEquals(expectedNumThrottles-1, countOfOutputLinesContaining("Still sleeping"));
assertEquals(1, countOfOutputLinesContaining("refreshed"));
assertEquals(23, getRequestCount(githubApi));

//Make sure no new output
ApiRateLimitChecker.ThrottleOnOver.checkApiRateLimit(listener, github);
assertEquals(1, countOfOutputLinesContaining("Sleeping for"));
assertEquals(expectedNumThrottles-1, countOfOutputLinesContaining("Still sleeping"));
assertEquals(1, countOfOutputLinesContaining("refreshed"));
assertEquals(24, getRequestCount(githubApi));
}

/**
Expand Down Expand Up @@ -234,26 +246,30 @@ public void ThrottleForNormalizeTestWithinIdeal() throws Exception {
scenarios.add(new RateLimit(limit, approximateIdeal - 101, soon));

// Check that we can back to our original throttle
scenarios.add(new RateLimit(limit, approximateIdeal - 100, soon));
// ignored as invalid by github-api library
scenarios.add(new RateLimit(limit, approximateIdeal - 100, new Date(soon.getTime() + 2000)));

// "Less" under the ideal but should recheck and throttle again
scenarios.add(new RateLimit(limit, approximateIdeal - 99, soon));
scenarios.add(new RateLimit(limit, approximateIdeal - 99, new Date(soon.getTime() + 2000)));

// Check that we are under our ideal so we should throttle
scenarios.add(new RateLimit(limit, approximateIdeal - 99, soon));

scenarios.add(new RateLimit(limit, approximateIdeal - 99, new Date(soon.getTime() + 2000)));

// Reset back to a full limit
scenarios.add(new RateLimit(limit, limit, soon));
scenarios.add(new RateLimit(limit, limit, new Date(soon.getTime() + 3000)));
setupStubs(scenarios);

// First check will say under budget (add counts)
ApiRateLimitChecker.ThrottleForNormalize.checkApiRateLimit(listener, github);

assertEquals(1, getRequestCount(githubApi));
assertEquals(1, countOfOutputLinesContaining("under budget"));
assertFalse(handler.getView().stream().anyMatch(m -> m.getMessage().contains("Sleeping")));

// Second check will go over budget
ApiRateLimitChecker.ThrottleForNormalize.checkApiRateLimit(listener, github);

assertEquals(9, getRequestCount(githubApi));
assertEquals(2, countOfOutputLinesContaining("rechecking"));
assertEquals(3, countOfOutputLinesContaining("Still sleeping"));
assertEquals(2, countOfOutputLinesContaining("Sleeping for"));
Expand Down Expand Up @@ -285,7 +301,7 @@ public void NormalizeThrottleWithBurnedBuffer() throws Exception {
// Trigger a throttle but we have burned our buffer
scenarios.add(new RateLimit(limit, 0, soon));
// Refresh rate limit
scenarios.add(new RateLimit(limit, limit, soon));
scenarios.add(new RateLimit(limit, limit, new Date(soon.getTime() + 2000)));
setupStubs(scenarios);

// Run check against API limit
Expand All @@ -303,6 +319,7 @@ public void NormalizeThrottleWithBurnedBuffer() throws Exception {
assertEquals(4, countOfOutputLinesContaining("Sleeping"));
// Expect that we stopped waiting on a refresh
assertEquals(1, countOfOutputLinesContaining("refreshed"));
assertEquals(6, getRequestCount(githubApi));
}

/**
Expand All @@ -329,7 +346,7 @@ public void OnOverThrottleTimingRateLimitCheck() throws Exception {
}

// finally, stop throttling by restoring quota
scenarios.add(new RateLimit(limit, limit, soon));
scenarios.add(new RateLimit(limit, limit, new Date(soon.getTime() + 2000)));
setupStubs(scenarios);

long start = System.currentTimeMillis();
Expand All @@ -339,12 +356,16 @@ public void OnOverThrottleTimingRateLimitCheck() throws Exception {
ApiRateLimitChecker.ThrottleOnOver.checkApiRateLimit(listener, github);
}

assertEquals(6, getRequestCount(githubApi));

//should be no output
assertEquals(0, countOfOutputLinesContaining("Sleeping"));

// check rate limit to hit the next 5 scenarios
ApiRateLimitChecker.ThrottleOnOver.checkApiRateLimit(listener, github);

assertEquals(13, getRequestCount(githubApi));

//want to make sure that the 5 API checks (the last one is resetting) are taking at least 1000 MS
assertTrue((System.currentTimeMillis() - start) > 1000);

Expand All @@ -354,6 +375,7 @@ public void OnOverThrottleTimingRateLimitCheck() throws Exception {

//no new output
ApiRateLimitChecker.ThrottleOnOver.checkApiRateLimit(listener, github);
assertEquals(14, getRequestCount(githubApi));
assertEquals(1, countOfOutputLinesContaining("Sleeping"));
assertEquals(expectedNumThrottles - 1, countOfOutputLinesContaining("Still sleeping"));
}
Expand Down Expand Up @@ -383,7 +405,9 @@ public void NormalizeThrottleTimingRateLimitCheck() throws Exception {
// Trigger a wait until rate limit
scenarios.add(new RateLimit(limit, approximateIdeal - burst, soon));
// Refresh rate limit
scenarios.add(new RateLimit(limit, limit, soon));
// github-api will ignore ratelimit responses that appear invalid
// Rate limit only goes up when the the reset date is later than previous records.
scenarios.add(new RateLimit(limit, limit, new Date(soon.getTime() + 2000)));
setupStubs(scenarios);
ApiRateLimitChecker.ThrottleForNormalize.checkApiRateLimit(listener, github);

Expand All @@ -393,6 +417,8 @@ public void NormalizeThrottleTimingRateLimitCheck() throws Exception {
// Run check
ApiRateLimitChecker.ThrottleForNormalize.checkApiRateLimit(listener, github);

assertEquals(6, getRequestCount(githubApi));

// Want to make sure that the 3 API checks are taking at least 600 MS
assertTrue((System.currentTimeMillis() - start) > 600);
// Expect a triggered throttle for normalize
Expand Down Expand Up @@ -425,31 +451,31 @@ public void NormalizeExpectedIdealOverTime() throws Exception {
// buffer for this limit will be limit/20 = 250
// burst for this will be limit/5 = 1000
// Ideal calculated at 45, 30, 15, and 0 minutes
int[] morePreciseIdeal = {612, 424, 237, 50};
int[] morePreciseIdeal = {50, 237, 424, 612};

// deadline set for those times as well
for (int i = 0; i < 4; i++) {
scenarios.add(new RateLimit(limit, morePreciseIdeal[i], new Date(start + TimeUnit.MINUTES.toMillis((3 - i) * 15))));
scenarios.add(new RateLimit(limit, morePreciseIdeal[i], new Date(start + TimeUnit.MINUTES.toMillis(i * 15))));
}
/*
* With the limit at 400: the burst will be limit/10 and buffer will be limit/20
*/
limit = 400;
morePreciseIdeal = new int[]{274, 189, 104, 20};
morePreciseIdeal = new int[]{20, 104, 189, 274};

// deadline set for those times as well
for (int i = 0; i < 4; i++) {
scenarios.add(new RateLimit(limit, morePreciseIdeal[i], new Date(start + TimeUnit.MINUTES.toMillis((3 - i) * 15))));
scenarios.add(new RateLimit(limit, morePreciseIdeal[i], new Date(start + TimeUnit.MINUTES.toMillis(i * 15))));
}
/*
* With the limit at 1000: the burst will be limit/5 and buffer will be 15
*/
limit = 200;
morePreciseIdeal = new int[]{138, 97, 56, 15};
morePreciseIdeal = new int[]{15, 56, 97, 138};

// deadline set for those times as well
for (int i = 0; i < 4; i++) {
scenarios.add(new RateLimit(limit, morePreciseIdeal[i], new Date(start + TimeUnit.MINUTES.toMillis((3 - i) * 15))));
scenarios.add(new RateLimit(limit, morePreciseIdeal[i], new Date(start + TimeUnit.MINUTES.toMillis(i * 15))));
}

setupStubs(scenarios);
Expand All @@ -458,6 +484,8 @@ public void NormalizeExpectedIdealOverTime() throws Exception {
ApiRateLimitChecker.ThrottleForNormalize.checkApiRateLimit(listener, github);
}

assertEquals(12, getRequestCount(githubApi));

// Expect a triggered throttle for normalize
assertEquals(12, countOfOutputLinesContaining("Current quota"));
// Making sure the budgets are correct
Expand All @@ -479,12 +507,16 @@ public void OnOverExpectedIdealOverTime() throws Exception {
List<RateLimit> scenarios = new ArrayList<>();
int limit = 1000;
// estimate the ideal(which does not apply in this scenario)
int[] morePreciseIdeal = {612, 424, 237, 49};
// Rate limit
int[] morePreciseIdeal = {49, 237, 424, 612};

// Rate limit records that expire early than the last returned are ignored as invalid
// Must be the same or greater
// deadline set for those times as well
for (int i = 0; i < 4; i++) {
scenarios.add(new RateLimit(limit, morePreciseIdeal[i], new Date(start + TimeUnit.MINUTES.toMillis((3 - i) * 15))));
scenarios.add(new RateLimit(limit, morePreciseIdeal[i], new Date(start + TimeUnit.MINUTES.toMillis((i) * 15))));
}

// Refresh rate limit
scenarios.add(new RateLimit(limit, limit, soon));
setupStubs(scenarios);
Expand All @@ -494,6 +526,8 @@ public void OnOverExpectedIdealOverTime() throws Exception {
ApiRateLimitChecker.ThrottleOnOver.checkApiRateLimit(listener, github);
}

assertEquals(6, getRequestCount(githubApi));

// Expect this to only get throttled when we are over the buffer limit
assertEquals(1, countOfOutputLinesContaining("Current quota"));
//Making sure the budget messages are correct
Expand All @@ -516,9 +550,9 @@ public void ExpectedResetTimingNormalize() throws Exception {
List<RateLimit> scenarios = new ArrayList<>();
int limit = 1000;
int buffer = 50;
scenarios.add(new RateLimit(limit, limit, soon));
//Giving a bit of time to make sure the setup happens on time
long start = System.currentTimeMillis() + 7000;
scenarios.add(new RateLimit(limit, limit, new Date(start)));

for (int i = 0; i <= 3; i++) {
scenarios.add(new RateLimit(limit, buffer - 5, new Date(start)));
Expand All @@ -540,6 +574,7 @@ public void ExpectedResetTimingNormalize() throws Exception {
// Expect a triggered throttle for normalize
assertEquals(2, countOfOutputLinesContaining("Current quota"));
assertEquals(2, countOfOutputLinesContaining("Still sleeping"));
assertEquals(6, getRequestCount(githubApi));
}

/**
Expand All @@ -557,9 +592,9 @@ public void ExpectedResetTimingOnOver() throws Exception {
List<RateLimit> scenarios = new ArrayList<>();
int limit = 1000;
int buffer = 50;
scenarios.add(new RateLimit(limit, limit, soon));
//Giving a bit of time to make sure the setup happens on time
long start = System.currentTimeMillis() + 7000;
scenarios.add(new RateLimit(limit, limit, new Date(start)));

for (int i = 0; i <= 3; i++) {
scenarios.add(new RateLimit(limit, buffer - 5, new Date(start)));
Expand All @@ -580,5 +615,6 @@ public void ExpectedResetTimingOnOver() throws Exception {
// We have 7 "notify" type messages and 2 "expired" type messages
assertEquals(2, countOfOutputLinesContaining("Current quota"));
assertEquals(2, countOfOutputLinesContaining("Still sleeping"));
assertEquals(6, getRequestCount(githubApi));
}
}