From bc8e2179e601a1836681562e785b4c1c16f9faef Mon Sep 17 00:00:00 2001 From: Ganesh Pagade Date: Sun, 21 Oct 2018 18:22:58 +0530 Subject: [PATCH 1/6] basic service with rate limit --- .../spring-cloud-zuul-throttling/pom.xml | 80 +++++++++++++++++++ .../ZuulRatelimitDemoApplication.java | 12 +++ .../controller/GreetingController.java | 23 ++++++ .../src/main/resources/application.yml | 23 ++++++ .../ZuulRatelimitDemoApplicationTests.java | 16 ++++ 5 files changed, 154 insertions(+) create mode 100644 spring-cloud/spring-cloud-zuul-throttling/pom.xml create mode 100644 spring-cloud/spring-cloud-zuul-throttling/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/ZuulRatelimitDemoApplication.java create mode 100644 spring-cloud/spring-cloud-zuul-throttling/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingController.java create mode 100644 spring-cloud/spring-cloud-zuul-throttling/src/main/resources/application.yml create mode 100644 spring-cloud/spring-cloud-zuul-throttling/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/ZuulRatelimitDemoApplicationTests.java diff --git a/spring-cloud/spring-cloud-zuul-throttling/pom.xml b/spring-cloud/spring-cloud-zuul-throttling/pom.xml new file mode 100644 index 0000000000..180cc96f00 --- /dev/null +++ b/spring-cloud/spring-cloud-zuul-throttling/pom.xml @@ -0,0 +1,80 @@ + + + 4.0.0 + + com.baeldung.spring.cloud + zuul-ratelimit-demo + 0.0.1-SNAPSHOT + jar + + zuul-ratelimit-demo + Demo project for Spring Boot + + + org.springframework.boot + spring-boot-starter-parent + 2.0.6.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + Finchley.SR1 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.cloud + spring-cloud-starter-netflix-zuul + + + com.marcosbarbero.cloud + spring-cloud-zuul-ratelimit + LATEST + + + org.springframework.boot + spring-boot-starter-data-jpa + + + com.h2database + h2 + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + diff --git a/spring-cloud/spring-cloud-zuul-throttling/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/ZuulRatelimitDemoApplication.java b/spring-cloud/spring-cloud-zuul-throttling/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/ZuulRatelimitDemoApplication.java new file mode 100644 index 0000000000..18a779f976 --- /dev/null +++ b/spring-cloud/spring-cloud-zuul-throttling/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/ZuulRatelimitDemoApplication.java @@ -0,0 +1,12 @@ +package com.baeldung.spring.cloud.zuulratelimitdemo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class ZuulRatelimitDemoApplication { + + public static void main(String[] args) { + SpringApplication.run(ZuulRatelimitDemoApplication.class, args); + } +} diff --git a/spring-cloud/spring-cloud-zuul-throttling/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingController.java b/spring-cloud/spring-cloud-zuul-throttling/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingController.java new file mode 100644 index 0000000000..ed380d17ea --- /dev/null +++ b/spring-cloud/spring-cloud-zuul-throttling/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingController.java @@ -0,0 +1,23 @@ +package com.baeldung.spring.cloud.zuulratelimitdemo.controller; + +import org.springframework.cloud.client.SpringCloudApplication; +import org.springframework.cloud.netflix.zuul.EnableZuulProxy; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +@EnableZuulProxy +@SpringCloudApplication +@RequestMapping("/greeting") +public class GreetingController { + + @GetMapping("/simple") + public ResponseEntity serviceA() { + return ResponseEntity.ok("Hi!"); + } + + @GetMapping("/advanced") + public ResponseEntity serviceB() { + return ResponseEntity.ok("Hello, how you doing?"); + } +} diff --git a/spring-cloud/spring-cloud-zuul-throttling/src/main/resources/application.yml b/spring-cloud/spring-cloud-zuul-throttling/src/main/resources/application.yml new file mode 100644 index 0000000000..d3afd34b2c --- /dev/null +++ b/spring-cloud/spring-cloud-zuul-throttling/src/main/resources/application.yml @@ -0,0 +1,23 @@ +zuul: + routes: + serviceSimple: + path: /greeting/simple + url: forward:/ + serviceAdvanced: + path: /greeting/advanced + url: forward:/ + ratelimit: + enabled: true + repository: JPA + policy-list: + serviceSimple: + - limit: 1 + refresh-interval: 60 + type: + - origin + serviceAdvanced: + - limit: 1 + refresh-interval: 2 + type: + - origin + strip-prefix: true diff --git a/spring-cloud/spring-cloud-zuul-throttling/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/ZuulRatelimitDemoApplicationTests.java b/spring-cloud/spring-cloud-zuul-throttling/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/ZuulRatelimitDemoApplicationTests.java new file mode 100644 index 0000000000..134d400b21 --- /dev/null +++ b/spring-cloud/spring-cloud-zuul-throttling/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/ZuulRatelimitDemoApplicationTests.java @@ -0,0 +1,16 @@ +package com.baeldung.spring.cloud.zuulratelimitdemo; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class ZuulRatelimitDemoApplicationTests { + + @Test + public void contextLoads() { + } + +} From e9bc235b1c4917968531c2a9cb50043fe560108d Mon Sep 17 00:00:00 2001 From: Ganesh Pagade Date: Sun, 21 Oct 2018 19:10:30 +0530 Subject: [PATCH 2/6] added test --- .../controller/GreetingController.java | 7 +- .../ZuulRatelimitDemoApplicationTests.java | 16 --- .../controller/GreetingControllerTest.java | 98 +++++++++++++++++++ 3 files changed, 103 insertions(+), 18 deletions(-) delete mode 100644 spring-cloud/spring-cloud-zuul-throttling/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/ZuulRatelimitDemoApplicationTests.java create mode 100644 spring-cloud/spring-cloud-zuul-throttling/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingControllerTest.java diff --git a/spring-cloud/spring-cloud-zuul-throttling/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingController.java b/spring-cloud/spring-cloud-zuul-throttling/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingController.java index ed380d17ea..4a27324b4d 100644 --- a/spring-cloud/spring-cloud-zuul-throttling/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingController.java +++ b/spring-cloud/spring-cloud-zuul-throttling/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingController.java @@ -11,13 +11,16 @@ import org.springframework.web.bind.annotation.RequestMapping; @RequestMapping("/greeting") public class GreetingController { + public static final String SIMPLE_RESPONSE = "Hi!"; + public static final String ADVANCED_RESPONSE = "Hello, how you doing?"; + @GetMapping("/simple") public ResponseEntity serviceA() { - return ResponseEntity.ok("Hi!"); + return ResponseEntity.ok(SIMPLE_RESPONSE); } @GetMapping("/advanced") public ResponseEntity serviceB() { - return ResponseEntity.ok("Hello, how you doing?"); + return ResponseEntity.ok(ADVANCED_RESPONSE); } } diff --git a/spring-cloud/spring-cloud-zuul-throttling/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/ZuulRatelimitDemoApplicationTests.java b/spring-cloud/spring-cloud-zuul-throttling/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/ZuulRatelimitDemoApplicationTests.java deleted file mode 100644 index 134d400b21..0000000000 --- a/spring-cloud/spring-cloud-zuul-throttling/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/ZuulRatelimitDemoApplicationTests.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.baeldung.spring.cloud.zuulratelimitdemo; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest -public class ZuulRatelimitDemoApplicationTests { - - @Test - public void contextLoads() { - } - -} diff --git a/spring-cloud/spring-cloud-zuul-throttling/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingControllerTest.java b/spring-cloud/spring-cloud-zuul-throttling/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingControllerTest.java new file mode 100644 index 0000000000..6b6dba1704 --- /dev/null +++ b/spring-cloud/spring-cloud-zuul-throttling/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingControllerTest.java @@ -0,0 +1,98 @@ +package com.baeldung.spring.cloud.zuulratelimitdemo.controller; + +import static com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.support.RateLimitConstants.HEADER_LIMIT; +import static com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.support.RateLimitConstants.HEADER_QUOTA; +import static com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.support.RateLimitConstants.HEADER_REMAINING; +import static com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.support.RateLimitConstants.HEADER_REMAINING_QUOTA; +import static com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.support.RateLimitConstants.HEADER_RESET; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.springframework.http.HttpStatus.OK; +import static org.springframework.http.HttpStatus.TOO_MANY_REQUESTS; + +import java.util.concurrent.TimeUnit; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit4.SpringRunner; + +@AutoConfigureTestDatabase +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +public class GreetingControllerTest { + + private static final String SIMPLE_GREETING = "/greeting/simple"; + private static final String ADVANCED_GREETING = "/greeting/advanced"; + + @Autowired + private TestRestTemplate restTemplate; + + @Test + public void testNotExceedingCapacityRequest() { + ResponseEntity response = this.restTemplate.getForEntity(SIMPLE_GREETING, String.class); + HttpHeaders headers = response.getHeaders(); + String key = "rate-limit-application_serviceSimple_127.0.0.1"; + assertHeaders(headers, key, false, false); + assertEquals(OK, response.getStatusCode()); + } + + @Test + public void testExceedingCapacity() throws InterruptedException { + ResponseEntity response = this.restTemplate + .getForEntity(ADVANCED_GREETING, String.class); + HttpHeaders headers = response.getHeaders(); + String key = "rate-limit-application_serviceAdvanced_127.0.0.1"; + assertHeaders(headers, key, false, false); + assertEquals(OK, response.getStatusCode()); + + for (int i = 0; i < 2; i++) { + response = this.restTemplate.getForEntity(ADVANCED_GREETING, String.class); + } + + assertEquals(TOO_MANY_REQUESTS, response.getStatusCode()); + assertNotEquals(GreetingController.ADVANCED_RESPONSE, response.getBody()); + + TimeUnit.SECONDS.sleep(2); + + response = this.restTemplate.getForEntity(ADVANCED_GREETING, String.class); + headers = response.getHeaders(); + assertHeaders(headers, key, false, false); + assertEquals(OK, response.getStatusCode()); + } + + private void assertHeaders(HttpHeaders headers, String key, boolean nullable, + boolean quotaHeaders) { + String quota = headers.getFirst(HEADER_QUOTA + key); + String remainingQuota = headers.getFirst(HEADER_REMAINING_QUOTA + key); + String limit = headers.getFirst(HEADER_LIMIT + key); + String remaining = headers.getFirst(HEADER_REMAINING + key); + String reset = headers.getFirst(HEADER_RESET + key); + + if (nullable) { + if (quotaHeaders) { + assertNull(quota); + assertNull(remainingQuota); + } else { + assertNull(limit); + assertNull(remaining); + } + assertNull(reset); + } else { + if (quotaHeaders) { + assertNotNull(quota); + assertNotNull(remainingQuota); + } else { + assertNotNull(limit); + assertNotNull(remaining); + } + assertNotNull(reset); + } + } +} From 87153bd9ff329f5505bb36f8b75acb28d54ff18f Mon Sep 17 00:00:00 2001 From: Ganesh Pagade Date: Mon, 22 Oct 2018 19:11:40 +0530 Subject: [PATCH 3/6] minor changes --- .../src/main/resources/application.yml | 2 +- .../controller/GreetingControllerTest.java | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/spring-cloud/spring-cloud-zuul-throttling/src/main/resources/application.yml b/spring-cloud/spring-cloud-zuul-throttling/src/main/resources/application.yml index d3afd34b2c..884ee9446e 100644 --- a/spring-cloud/spring-cloud-zuul-throttling/src/main/resources/application.yml +++ b/spring-cloud/spring-cloud-zuul-throttling/src/main/resources/application.yml @@ -11,7 +11,7 @@ zuul: repository: JPA policy-list: serviceSimple: - - limit: 1 + - limit: 5 refresh-interval: 60 type: - origin diff --git a/spring-cloud/spring-cloud-zuul-throttling/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingControllerTest.java b/spring-cloud/spring-cloud-zuul-throttling/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingControllerTest.java index 6b6dba1704..360d005c43 100644 --- a/spring-cloud/spring-cloud-zuul-throttling/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingControllerTest.java +++ b/spring-cloud/spring-cloud-zuul-throttling/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingControllerTest.java @@ -35,7 +35,7 @@ public class GreetingControllerTest { private TestRestTemplate restTemplate; @Test - public void testNotExceedingCapacityRequest() { + public void whenRequestNotExceedingCapacity_thenReturnOkResponse() { ResponseEntity response = this.restTemplate.getForEntity(SIMPLE_GREETING, String.class); HttpHeaders headers = response.getHeaders(); String key = "rate-limit-application_serviceSimple_127.0.0.1"; @@ -44,7 +44,7 @@ public class GreetingControllerTest { } @Test - public void testExceedingCapacity() throws InterruptedException { + public void whenRequestExceedingCapacity_thenReturnTooManyRequestsResponse() throws InterruptedException { ResponseEntity response = this.restTemplate .getForEntity(ADVANCED_GREETING, String.class); HttpHeaders headers = response.getHeaders(); @@ -95,4 +95,6 @@ public class GreetingControllerTest { assertNotNull(reset); } } + + } From f34d44faaa742da46467a00562380669f4b4c881 Mon Sep 17 00:00:00 2001 From: Ganesh Pagade Date: Fri, 26 Oct 2018 10:21:35 +0530 Subject: [PATCH 4/6] fixes --- .../spring-cloud-zuul-throttling/pom.xml | 2 +- .../ZuulRatelimitDemoApplication.java | 47 ++++++- .../controller/GreetingController.java | 20 +-- .../src/main/resources/application.yml | 18 +-- .../controller/GreetingControllerTest.java | 125 ++++++++++-------- 5 files changed, 133 insertions(+), 79 deletions(-) diff --git a/spring-cloud/spring-cloud-zuul-throttling/pom.xml b/spring-cloud/spring-cloud-zuul-throttling/pom.xml index 180cc96f00..b34ade662a 100644 --- a/spring-cloud/spring-cloud-zuul-throttling/pom.xml +++ b/spring-cloud/spring-cloud-zuul-throttling/pom.xml @@ -37,7 +37,7 @@ com.marcosbarbero.cloud spring-cloud-zuul-ratelimit - LATEST + 2.2.0.RELEASE org.springframework.boot diff --git a/spring-cloud/spring-cloud-zuul-throttling/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/ZuulRatelimitDemoApplication.java b/spring-cloud/spring-cloud-zuul-throttling/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/ZuulRatelimitDemoApplication.java index 18a779f976..cc13b7a046 100644 --- a/spring-cloud/spring-cloud-zuul-throttling/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/ZuulRatelimitDemoApplication.java +++ b/spring-cloud/spring-cloud-zuul-throttling/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/ZuulRatelimitDemoApplication.java @@ -1,12 +1,53 @@ package com.baeldung.spring.cloud.zuulratelimitdemo; +import javax.servlet.http.HttpServletRequest; + import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.netflix.zuul.filters.Route; +import org.springframework.context.annotation.Bean; + +import com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.config.RateLimitKeyGenerator; +import com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.config.RateLimitUtils; +import com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.config.properties.RateLimitProperties; +import com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.config.repository.RateLimiterErrorHandler; +import com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.config.repository.DefaultRateLimiterErrorHandler; +import com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.support.DefaultRateLimitKeyGenerator; @SpringBootApplication public class ZuulRatelimitDemoApplication { - public static void main(String[] args) { - SpringApplication.run(ZuulRatelimitDemoApplication.class, args); - } + public static void main(String[] args) { + SpringApplication.run(ZuulRatelimitDemoApplication.class, args); + } + + @Bean + public RateLimitKeyGenerator ratelimitKeyGenerator(RateLimitProperties properties, RateLimitUtils rateLimitUtils) { + return new DefaultRateLimitKeyGenerator(properties, rateLimitUtils) { + @Override + public String key(HttpServletRequest request, Route route, RateLimitProperties.Policy policy) { + return super.key(request, route, policy) + ":" + request.getMethod(); + } + }; + } + + @Bean + public RateLimiterErrorHandler rateLimitErrorHandler() { + return new DefaultRateLimiterErrorHandler() { + @Override + public void handleSaveError(String key, Exception e) { + // custom code + } + + @Override + public void handleFetchError(String key, Exception e) { + // custom code + } + + @Override + public void handleError(String msg, Exception e) { + // custom code + } + }; + } } diff --git a/spring-cloud/spring-cloud-zuul-throttling/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingController.java b/spring-cloud/spring-cloud-zuul-throttling/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingController.java index 4a27324b4d..f0facc621a 100644 --- a/spring-cloud/spring-cloud-zuul-throttling/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingController.java +++ b/spring-cloud/spring-cloud-zuul-throttling/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingController.java @@ -11,16 +11,16 @@ import org.springframework.web.bind.annotation.RequestMapping; @RequestMapping("/greeting") public class GreetingController { - public static final String SIMPLE_RESPONSE = "Hi!"; - public static final String ADVANCED_RESPONSE = "Hello, how you doing?"; + public static final String SIMPLE_RESPONSE = "Hi!"; + public static final String ADVANCED_RESPONSE = "Hello, how you doing?"; - @GetMapping("/simple") - public ResponseEntity serviceA() { - return ResponseEntity.ok(SIMPLE_RESPONSE); - } + @GetMapping("/simple") + public ResponseEntity getSimple() { + return ResponseEntity.ok(SIMPLE_RESPONSE); + } - @GetMapping("/advanced") - public ResponseEntity serviceB() { - return ResponseEntity.ok(ADVANCED_RESPONSE); - } + @GetMapping("/advanced") + public ResponseEntity getAdvanced() { + return ResponseEntity.ok(ADVANCED_RESPONSE); + } } diff --git a/spring-cloud/spring-cloud-zuul-throttling/src/main/resources/application.yml b/spring-cloud/spring-cloud-zuul-throttling/src/main/resources/application.yml index 884ee9446e..86a29ca06d 100644 --- a/spring-cloud/spring-cloud-zuul-throttling/src/main/resources/application.yml +++ b/spring-cloud/spring-cloud-zuul-throttling/src/main/resources/application.yml @@ -11,13 +11,13 @@ zuul: repository: JPA policy-list: serviceSimple: - - limit: 5 - refresh-interval: 60 - type: - - origin + - limit: 5 + refresh-interval: 60 + type: + - origin serviceAdvanced: - - limit: 1 - refresh-interval: 2 - type: - - origin - strip-prefix: true + - limit: 1 + refresh-interval: 2 + type: + - origin + strip-prefix: true \ No newline at end of file diff --git a/spring-cloud/spring-cloud-zuul-throttling/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingControllerTest.java b/spring-cloud/spring-cloud-zuul-throttling/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingControllerTest.java index 360d005c43..fe81838d5d 100644 --- a/spring-cloud/spring-cloud-zuul-throttling/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingControllerTest.java +++ b/spring-cloud/spring-cloud-zuul-throttling/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingControllerTest.java @@ -28,73 +28,86 @@ import org.springframework.test.context.junit4.SpringRunner; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class GreetingControllerTest { - private static final String SIMPLE_GREETING = "/greeting/simple"; - private static final String ADVANCED_GREETING = "/greeting/advanced"; + private static final String SIMPLE_GREETING = "/greeting/simple"; + private static final String ADVANCED_GREETING = "/greeting/advanced"; - @Autowired - private TestRestTemplate restTemplate; + @Autowired + private TestRestTemplate restTemplate; - @Test - public void whenRequestNotExceedingCapacity_thenReturnOkResponse() { - ResponseEntity response = this.restTemplate.getForEntity(SIMPLE_GREETING, String.class); - HttpHeaders headers = response.getHeaders(); - String key = "rate-limit-application_serviceSimple_127.0.0.1"; - assertHeaders(headers, key, false, false); - assertEquals(OK, response.getStatusCode()); - } + @Test + public void whenRequestNotExceedingCapacity_thenReturnOkResponse() { + ResponseEntity response = this.restTemplate.getForEntity(SIMPLE_GREETING, String.class); + HttpHeaders headers = response.getHeaders(); + String key = "rate-limit-application_serviceSimple_127.0.0.1"; - @Test - public void whenRequestExceedingCapacity_thenReturnTooManyRequestsResponse() throws InterruptedException { - ResponseEntity response = this.restTemplate - .getForEntity(ADVANCED_GREETING, String.class); - HttpHeaders headers = response.getHeaders(); - String key = "rate-limit-application_serviceAdvanced_127.0.0.1"; - assertHeaders(headers, key, false, false); - assertEquals(OK, response.getStatusCode()); + String limit = headers.getFirst(HEADER_LIMIT + key); + String remaining = headers.getFirst(HEADER_REMAINING + key); + String reset = headers.getFirst(HEADER_RESET + key); - for (int i = 0; i < 2; i++) { - response = this.restTemplate.getForEntity(ADVANCED_GREETING, String.class); + assertEquals(limit, "5"); + assertEquals(remaining, "4"); + assertEquals(reset, "60000"); + + assertEquals(OK, response.getStatusCode()); } - assertEquals(TOO_MANY_REQUESTS, response.getStatusCode()); - assertNotEquals(GreetingController.ADVANCED_RESPONSE, response.getBody()); + @Test + public void whenRequestExceedingCapacity_thenReturnTooManyRequestsResponse() throws InterruptedException { + ResponseEntity response = this.restTemplate.getForEntity(ADVANCED_GREETING, String.class); + HttpHeaders headers = response.getHeaders(); + String key = "rate-limit-application_serviceAdvanced_127.0.0.1"; + assertHeaders(headers, key, false, false); + assertEquals(OK, response.getStatusCode()); - TimeUnit.SECONDS.sleep(2); + for (int i = 0; i < 2; i++) { + response = this.restTemplate.getForEntity(ADVANCED_GREETING, String.class); + } - response = this.restTemplate.getForEntity(ADVANCED_GREETING, String.class); - headers = response.getHeaders(); - assertHeaders(headers, key, false, false); - assertEquals(OK, response.getStatusCode()); - } + headers = response.getHeaders(); + String limit = headers.getFirst(HEADER_LIMIT + key); + String remaining = headers.getFirst(HEADER_REMAINING + key); + String reset = headers.getFirst(HEADER_RESET + key); - private void assertHeaders(HttpHeaders headers, String key, boolean nullable, - boolean quotaHeaders) { - String quota = headers.getFirst(HEADER_QUOTA + key); - String remainingQuota = headers.getFirst(HEADER_REMAINING_QUOTA + key); - String limit = headers.getFirst(HEADER_LIMIT + key); - String remaining = headers.getFirst(HEADER_REMAINING + key); - String reset = headers.getFirst(HEADER_RESET + key); + assertEquals(limit, "1"); + assertEquals(remaining, "0"); + assertNotEquals(reset, "2000"); - if (nullable) { - if (quotaHeaders) { - assertNull(quota); - assertNull(remainingQuota); - } else { - assertNull(limit); - assertNull(remaining); - } - assertNull(reset); - } else { - if (quotaHeaders) { - assertNotNull(quota); - assertNotNull(remainingQuota); - } else { - assertNotNull(limit); - assertNotNull(remaining); - } - assertNotNull(reset); + assertEquals(TOO_MANY_REQUESTS, response.getStatusCode()); + assertNotEquals(GreetingController.ADVANCED_RESPONSE, response.getBody()); + + TimeUnit.SECONDS.sleep(2); + + response = this.restTemplate.getForEntity(ADVANCED_GREETING, String.class); + headers = response.getHeaders(); + assertHeaders(headers, key, false, false); + assertEquals(OK, response.getStatusCode()); } - } + private void assertHeaders(HttpHeaders headers, String key, boolean nullable, boolean quotaHeaders) { + String quota = headers.getFirst(HEADER_QUOTA + key); + String remainingQuota = headers.getFirst(HEADER_REMAINING_QUOTA + key); + String limit = headers.getFirst(HEADER_LIMIT + key); + String remaining = headers.getFirst(HEADER_REMAINING + key); + String reset = headers.getFirst(HEADER_RESET + key); + if (nullable) { + if (quotaHeaders) { + assertNull(quota); + assertNull(remainingQuota); + } else { + assertNull(limit); + assertNull(remaining); + } + assertNull(reset); + } else { + if (quotaHeaders) { + assertNotNull(quota); + assertNotNull(remainingQuota); + } else { + assertNotNull(limit); + assertNotNull(remaining); + } + assertNotNull(reset); + } + } } From 21d6a0d856a04b416af0480bf84258337f4c0c1b Mon Sep 17 00:00:00 2001 From: Ganesh Pagade Date: Tue, 30 Oct 2018 00:05:39 +0530 Subject: [PATCH 5/6] renamed dir and artifact --- .../pom.xml | 4 ++-- .../cloud/zuulratelimitdemo/ZuulRatelimitDemoApplication.java | 0 .../zuulratelimitdemo/controller/GreetingController.java | 0 .../src/main/resources/application.yml | 0 .../zuulratelimitdemo/controller/GreetingControllerTest.java | 0 5 files changed, 2 insertions(+), 2 deletions(-) rename spring-cloud/{spring-cloud-zuul-throttling => spring-cloud-zuul-ratelimit}/pom.xml (95%) rename spring-cloud/{spring-cloud-zuul-throttling => spring-cloud-zuul-ratelimit}/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/ZuulRatelimitDemoApplication.java (100%) rename spring-cloud/{spring-cloud-zuul-throttling => spring-cloud-zuul-ratelimit}/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingController.java (100%) rename spring-cloud/{spring-cloud-zuul-throttling => spring-cloud-zuul-ratelimit}/src/main/resources/application.yml (100%) rename spring-cloud/{spring-cloud-zuul-throttling => spring-cloud-zuul-ratelimit}/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingControllerTest.java (100%) diff --git a/spring-cloud/spring-cloud-zuul-throttling/pom.xml b/spring-cloud/spring-cloud-zuul-ratelimit/pom.xml similarity index 95% rename from spring-cloud/spring-cloud-zuul-throttling/pom.xml rename to spring-cloud/spring-cloud-zuul-ratelimit/pom.xml index b34ade662a..46139b4f57 100644 --- a/spring-cloud/spring-cloud-zuul-throttling/pom.xml +++ b/spring-cloud/spring-cloud-zuul-ratelimit/pom.xml @@ -4,11 +4,11 @@ 4.0.0 com.baeldung.spring.cloud - zuul-ratelimit-demo + spring-cloud-zuul-ratelimit 0.0.1-SNAPSHOT jar - zuul-ratelimit-demo + spring-cloud-zuul-ratelimit Demo project for Spring Boot diff --git a/spring-cloud/spring-cloud-zuul-throttling/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/ZuulRatelimitDemoApplication.java b/spring-cloud/spring-cloud-zuul-ratelimit/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/ZuulRatelimitDemoApplication.java similarity index 100% rename from spring-cloud/spring-cloud-zuul-throttling/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/ZuulRatelimitDemoApplication.java rename to spring-cloud/spring-cloud-zuul-ratelimit/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/ZuulRatelimitDemoApplication.java diff --git a/spring-cloud/spring-cloud-zuul-throttling/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingController.java b/spring-cloud/spring-cloud-zuul-ratelimit/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingController.java similarity index 100% rename from spring-cloud/spring-cloud-zuul-throttling/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingController.java rename to spring-cloud/spring-cloud-zuul-ratelimit/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingController.java diff --git a/spring-cloud/spring-cloud-zuul-throttling/src/main/resources/application.yml b/spring-cloud/spring-cloud-zuul-ratelimit/src/main/resources/application.yml similarity index 100% rename from spring-cloud/spring-cloud-zuul-throttling/src/main/resources/application.yml rename to spring-cloud/spring-cloud-zuul-ratelimit/src/main/resources/application.yml diff --git a/spring-cloud/spring-cloud-zuul-throttling/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingControllerTest.java b/spring-cloud/spring-cloud-zuul-ratelimit/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingControllerTest.java similarity index 100% rename from spring-cloud/spring-cloud-zuul-throttling/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingControllerTest.java rename to spring-cloud/spring-cloud-zuul-ratelimit/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingControllerTest.java From 6f87196dc9fc31e5ddf83763a71da4350ac2d2e4 Mon Sep 17 00:00:00 2001 From: Ganesh Pagade Date: Thu, 1 Nov 2018 14:08:32 +0530 Subject: [PATCH 6/6] minor fixes --- .../ZuulRatelimitDemoApplication.java | 47 ++----------------- .../controller/GreetingController.java | 13 ++--- .../controller/GreetingControllerTest.java | 1 - 3 files changed, 8 insertions(+), 53 deletions(-) diff --git a/spring-cloud/spring-cloud-zuul-ratelimit/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/ZuulRatelimitDemoApplication.java b/spring-cloud/spring-cloud-zuul-ratelimit/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/ZuulRatelimitDemoApplication.java index cc13b7a046..9b53099768 100644 --- a/spring-cloud/spring-cloud-zuul-ratelimit/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/ZuulRatelimitDemoApplication.java +++ b/spring-cloud/spring-cloud-zuul-ratelimit/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/ZuulRatelimitDemoApplication.java @@ -1,53 +1,14 @@ package com.baeldung.spring.cloud.zuulratelimitdemo; -import javax.servlet.http.HttpServletRequest; - import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.cloud.netflix.zuul.filters.Route; -import org.springframework.context.annotation.Bean; +import org.springframework.cloud.client.SpringCloudApplication; +import org.springframework.cloud.netflix.zuul.EnableZuulProxy; -import com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.config.RateLimitKeyGenerator; -import com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.config.RateLimitUtils; -import com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.config.properties.RateLimitProperties; -import com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.config.repository.RateLimiterErrorHandler; -import com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.config.repository.DefaultRateLimiterErrorHandler; -import com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.support.DefaultRateLimitKeyGenerator; - -@SpringBootApplication +@EnableZuulProxy +@SpringCloudApplication public class ZuulRatelimitDemoApplication { public static void main(String[] args) { SpringApplication.run(ZuulRatelimitDemoApplication.class, args); } - - @Bean - public RateLimitKeyGenerator ratelimitKeyGenerator(RateLimitProperties properties, RateLimitUtils rateLimitUtils) { - return new DefaultRateLimitKeyGenerator(properties, rateLimitUtils) { - @Override - public String key(HttpServletRequest request, Route route, RateLimitProperties.Policy policy) { - return super.key(request, route, policy) + ":" + request.getMethod(); - } - }; - } - - @Bean - public RateLimiterErrorHandler rateLimitErrorHandler() { - return new DefaultRateLimiterErrorHandler() { - @Override - public void handleSaveError(String key, Exception e) { - // custom code - } - - @Override - public void handleFetchError(String key, Exception e) { - // custom code - } - - @Override - public void handleError(String msg, Exception e) { - // custom code - } - }; - } } diff --git a/spring-cloud/spring-cloud-zuul-ratelimit/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingController.java b/spring-cloud/spring-cloud-zuul-ratelimit/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingController.java index f0facc621a..3f2ec4822f 100644 --- a/spring-cloud/spring-cloud-zuul-ratelimit/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingController.java +++ b/spring-cloud/spring-cloud-zuul-ratelimit/src/main/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingController.java @@ -1,26 +1,21 @@ package com.baeldung.spring.cloud.zuulratelimitdemo.controller; -import org.springframework.cloud.client.SpringCloudApplication; -import org.springframework.cloud.netflix.zuul.EnableZuulProxy; import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; -@EnableZuulProxy -@SpringCloudApplication +@Controller @RequestMapping("/greeting") public class GreetingController { - public static final String SIMPLE_RESPONSE = "Hi!"; - public static final String ADVANCED_RESPONSE = "Hello, how you doing?"; - @GetMapping("/simple") public ResponseEntity getSimple() { - return ResponseEntity.ok(SIMPLE_RESPONSE); + return ResponseEntity.ok("Hi!"); } @GetMapping("/advanced") public ResponseEntity getAdvanced() { - return ResponseEntity.ok(ADVANCED_RESPONSE); + return ResponseEntity.ok("Hello, how you doing?"); } } diff --git a/spring-cloud/spring-cloud-zuul-ratelimit/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingControllerTest.java b/spring-cloud/spring-cloud-zuul-ratelimit/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingControllerTest.java index fe81838d5d..d51f881112 100644 --- a/spring-cloud/spring-cloud-zuul-ratelimit/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingControllerTest.java +++ b/spring-cloud/spring-cloud-zuul-ratelimit/src/test/java/com/baeldung/spring/cloud/zuulratelimitdemo/controller/GreetingControllerTest.java @@ -73,7 +73,6 @@ public class GreetingControllerTest { assertNotEquals(reset, "2000"); assertEquals(TOO_MANY_REQUESTS, response.getStatusCode()); - assertNotEquals(GreetingController.ADVANCED_RESPONSE, response.getBody()); TimeUnit.SECONDS.sleep(2);