/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.component.reactive.streams;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import org.apache.camel.RoutesBuilder;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.component.reactive.streams.api.CamelReactiveStreams;
import org.apache.camel.component.reactive.streams.api.CamelReactiveStreamsService;
import org.apache.camel.test.junit4.CamelTestSupport;
import org.junit.Test;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
/**
* Test the number of refill requests that are sent to a published from a Camel consumer.
*/
public class RequestRefillTest extends CamelTestSupport {
@Test
public void testUnboundedRequests() throws Exception {
int numReqs = 100;
List<Long> requests = executeTest("unbounded", numReqs);
assertEquals(1, requests.size());
assertEquals(Long.MAX_VALUE, requests.get(0).longValue());
}
@Test
public void testUnboundedRequestsWatermarkNoEffect() throws Exception {
int numReqs = 100;
List<Long> requests = executeTest("unbounded-100", numReqs);
assertEquals(1, requests.size());
assertEquals(Long.MAX_VALUE, requests.get(0).longValue());
}
@Test
public void testBoundedRequests() throws Exception {
int numReqs = 100;
List<Long> requests = executeTest("bounded", numReqs);
assertTrue(requests.size() >= numReqs / 10);
}
@Test
public void testBoundedRequestsPercentageRefill() throws Exception {
int numReqs = 120;
List<Long> requests0 = executeTest("bounded-0", numReqs);
List<Long> requests10 = executeTest("bounded-10", numReqs);
List<Long> requests25 = executeTest("bounded", numReqs);
List<Long> requests80 = executeTest("bounded-80", numReqs);
List<Long> requests100 = executeTest("bounded-100", numReqs);
assertTrue(requests0.size() <= requests10.size()); // too close
assertTrue(requests10.size() < requests25.size());
assertTrue(requests25.size() < requests80.size());
assertTrue(requests80.size() < requests100.size());
}
private List<Long> executeTest(String name, int numReqs) throws InterruptedException {
List<Long> requests = Collections.synchronizedList(new LinkedList<>());
Publisher<Long> nums = createPublisher(numReqs, requests);
MockEndpoint mock = getMockEndpoint("mock:" + name + "-endpoint");
mock.expectedMessageCount(numReqs);
CamelReactiveStreamsService rxCamel = CamelReactiveStreams.get(context());
nums.subscribe(rxCamel.streamSubscriber(name, Long.class));
mock.assertIsSatisfied();
Long sum = mock.getExchanges().stream().map(x -> x.getIn().getBody(Long.class)).reduce((l, r) -> l + r).get();
assertEquals(numReqs * (numReqs + 1) / 2, sum.longValue());
return requests;
}
private Publisher<Long> createPublisher(final int numReqs, final List<Long> requests) {
return Flux.range(1, numReqs).map(Long::valueOf).doOnRequest(requests::add);
}
@Override
protected RoutesBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
@Override
public void configure() throws Exception {
from("reactive-streams:unbounded?maxInflightExchanges=-1")
.delayer(1)
.to("mock:unbounded-endpoint");
from("reactive-streams:unbounded-100?maxInflightExchanges=-1&exchangesRefillLowWatermark=1")
.delayer(1)
.to("mock:unbounded-100-endpoint");
from("reactive-streams:bounded?maxInflightExchanges=10")
.delayer(1)
.to("mock:bounded-endpoint");
from("reactive-streams:bounded-0?maxInflightExchanges=10&exchangesRefillLowWatermark=0")
.delayer(1)
.to("mock:bounded-0-endpoint");
from("reactive-streams:bounded-10?maxInflightExchanges=10&exchangesRefillLowWatermark=0.1")
.delayer(1)
.to("mock:bounded-10-endpoint");
from("reactive-streams:bounded-80?maxInflightExchanges=10&exchangesRefillLowWatermark=0.8")
.delayer(1)
.to("mock:bounded-80-endpoint");
from("reactive-streams:bounded-100?maxInflightExchanges=10&exchangesRefillLowWatermark=1")
.delayer(1)
.to("mock:bounded-100-endpoint");
}
};
}
}