2 * Copyright (c) 2010-2024 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.http;
15 import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
16 import static com.github.tomakehurst.wiremock.client.WireMock.get;
17 import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
18 import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
19 import static org.hamcrest.CoreMatchers.allOf;
20 import static org.hamcrest.CoreMatchers.anyOf;
21 import static org.hamcrest.MatcherAssert.assertThat;
22 import static org.hamcrest.Matchers.equalTo;
23 import static org.hamcrest.Matchers.greaterThanOrEqualTo;
24 import static org.hamcrest.Matchers.lessThan;
25 import static org.junit.jupiter.api.Assertions.assertEquals;
26 import static org.junit.jupiter.api.Assertions.assertNotEquals;
29 import java.util.List;
30 import java.util.concurrent.CompletableFuture;
31 import java.util.concurrent.CopyOnWriteArrayList;
33 import org.eclipse.jdt.annotation.NonNullByDefault;
34 import org.eclipse.jetty.client.api.ContentResponse;
35 import org.eclipse.jetty.client.api.Request;
36 import org.eclipse.jetty.http.HttpMethod;
37 import org.junit.jupiter.api.AfterEach;
38 import org.junit.jupiter.api.Test;
39 import org.junit.jupiter.api.TestInstance;
40 import org.openhab.binding.http.internal.http.RateLimitedHttpClient;
43 * The {@link RateLimitedHttpClientTest} implements tests for the {@link RateLimitedHttpClient}
45 * @author Jan N. Klug - Initial contribution
48 @TestInstance(TestInstance.Lifecycle.PER_CLASS)
49 public class RateLimitedHttpClientTest extends AbstractWireMockTest {
50 private static final String TEST_LOCATION = "/testlocation";
51 private static final String TEST_CONTENT = "TESTCONTENT";
53 private List<Response> responses = new CopyOnWriteArrayList<>();
56 public void cleanUpTest() {
62 public void testWithoutLimit() {
63 doLimitTest(0, List.of(false, false));
65 // we except to receive the responses in the correct order
66 assertEquals(0, responses.get(0).seqNumber);
67 assertEquals(1, responses.get(1).seqNumber);
69 // we expect a short delay between both requests, but less than 100ms
70 long msBetween = responses.get(1).time - responses.get(0).time;
71 assertThat((int) msBetween, allOf(greaterThanOrEqualTo(0), lessThan(100)));
75 public void testWithLimit() {
76 doLimitTest(500, List.of(false, false));
77 // we except to receive the responses in the correct order
78 assertEquals(0, responses.get(0).seqNumber);
79 assertEquals(1, responses.get(1).seqNumber);
81 // we expect at least 500ms delay between both requests, but less than 500+100=600ms
82 long msBetween = responses.get(1).time - responses.get(0).time;
83 assertThat((int) msBetween, allOf(greaterThanOrEqualTo(500), lessThan(600)));
87 public void testWithLimitAndPriority() {
88 doLimitTest(500, List.of(false, false, true));
90 // we expect to receive the responses of request 3 before request two, exact order of 1 and 3 depends on timing,
92 assertThat(responses.get(0).seqNumber, anyOf(equalTo(0), equalTo(2)));
93 assertThat(responses.get(1).seqNumber, anyOf(equalTo(0), equalTo(2)));
94 assertNotEquals(responses.get(1).seqNumber, responses.get(0).seqNumber);
95 assertEquals(1, responses.get(2).seqNumber);
97 // we expect at least 2*500=1000ms delay between the first and last request, but less than 2*500+100=1100 ms
98 long msBetween = responses.get(2).time - responses.get(0).time;
99 assertThat((int) msBetween, allOf(greaterThanOrEqualTo(1000), lessThan(1100)));
102 private List<Response> doLimitTest(int setDelay, List<Boolean> config) {
103 stubFor(get(urlEqualTo(TEST_LOCATION)).willReturn(aResponse().withBody(TEST_CONTENT)));
105 RateLimitedHttpClient rateLimitedHttpClient = new RateLimitedHttpClient(httpClient, scheduler);
106 rateLimitedHttpClient.setDelay(setDelay);
108 URI url = URI.create("http://localhost:" + port + TEST_LOCATION);
111 for (boolean priority : config) {
112 int nextSeqNumber = seqNumber++;
113 CompletableFuture<Request> requestFuture;
116 requestFuture = rateLimitedHttpClient.newPriorityRequest(url, HttpMethod.GET, "", null);
118 requestFuture = rateLimitedHttpClient.newRequest(url, HttpMethod.GET, "", null);
121 requestFuture.thenAccept(request -> {
123 responses.add(new Response(nextSeqNumber, request.send()));
124 } catch (Exception e) {
129 // wait until we got all results
130 waitForAssert(() -> assertEquals(config.size(), responses.size()));
131 rateLimitedHttpClient.shutdown();
136 private static class Response {
137 public final int seqNumber;
138 public final long time = System.currentTimeMillis();
139 public final String content;
141 public Response(int seqNumber, ContentResponse contentResponse) {
142 this.seqNumber = seqNumber;
143 this.content = contentResponse.getContentAsString();