reactor.rabbitmq.LazyChannelPoolTests.java Source code

Java tutorial

Introduction

Here is the source code for reactor.rabbitmq.LazyChannelPoolTests.java

Source

/*
 * Copyright (c) 2019 Pivotal Software Inc, All Rights Reserved.
 *
 * Licensed 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
 *
 *       https://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 reactor.rabbitmq;

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import reactor.test.scheduler.VirtualTimeScheduler;

import java.io.IOException;
import java.time.Duration;

import static java.time.Duration.ofSeconds;
import static org.mockito.Mockito.*;

class LazyChannelPoolTests {

    LazyChannelPool lazyChannelPool;

    Connection connection;
    Channel channel1, channel2, channel3;

    @BeforeEach
    void setUp() throws IOException {
        connection = mock(Connection.class);
        when(connection.isOpen()).thenReturn(true);
        channel1 = channel(1);
        channel2 = channel(2);
        channel3 = channel(3);
        when(connection.createChannel()).thenReturn(channel1, channel2, channel3);
    }

    @Test
    void testChannelPoolLazyInitialization() throws Exception {
        int maxChannelPoolSize = 2;
        ChannelPoolOptions channelPoolOptions = new ChannelPoolOptions().maxCacheSize(maxChannelPoolSize)
                .subscriptionScheduler(VirtualTimeScheduler.create());
        lazyChannelPool = new LazyChannelPool(Mono.just(connection), channelPoolOptions);

        StepVerifier.withVirtualTime(() -> Mono.when(
                // 1#
                useChannelFromStartUntil(ofSeconds(1)),
                // 2#
                useChannelBetween(ofSeconds(2), ofSeconds(3)))).expectSubscription().thenAwait(ofSeconds(3))
                .verifyComplete();

        // Expectations, numbers on the left mean elapsed time in seconds
        // 0 -> 1# creates channel1
        // 1 -> 1# releases channel1, 1# adds channel1 to pool
        // 2 -> 2# obtains channel1 from pool
        // 3 -> 2# releases channel1, 2# adds channel1 to pool

        verifyBasicPublish(channel1, 2);
        verifyBasicPublishNever(channel2);
        verify(channel1, never()).close();

        lazyChannelPool.close();

        verify(channel1).close();
        verify(channel2, never()).close();
    }

    @Test
    void testChannelPoolExceedsMaxPoolSize() throws Exception {
        int maxChannelPoolSize = 2;
        ChannelPoolOptions channelPoolOptions = new ChannelPoolOptions().maxCacheSize(maxChannelPoolSize)
                .subscriptionScheduler(VirtualTimeScheduler.create());
        lazyChannelPool = new LazyChannelPool(Mono.just(connection), channelPoolOptions);

        StepVerifier.withVirtualTime(() -> Mono.when(
                // 1#
                useChannelBetween(ofSeconds(1), ofSeconds(4)),
                // 2#
                useChannelBetween(ofSeconds(2), ofSeconds(5)),
                // 3#
                useChannelBetween(ofSeconds(3), ofSeconds(6)))).expectSubscription().thenAwait(ofSeconds(6))
                .verifyComplete();

        // Expectations, numbers on the left mean elapsed time in seconds
        // 1 -> 1# creates channel1
        // 2 -> 2# creates channel2
        // 3 -> 3# creates channel3
        // 4 -> 1# releases channel1, 1# adds channel1 to pool
        // 5 -> 2# releases channel2, 2# adds channel2 to pool
        // 6 -> 3# releases channel3, 3# closes channel3 (pool is full)

        verifyBasicPublishOnce(channel1);
        verifyBasicPublishOnce(channel2);
        verifyBasicPublishOnce(channel3);
        verify(channel1, never()).close();
        verify(channel2, never()).close();
        verify(channel3).close();

        lazyChannelPool.close();

        verify(channel1).close();
        verify(channel2).close();
    }

    @Test
    void testChannelPool() throws Exception {
        int maxChannelPoolSize = 1;
        ChannelPoolOptions channelPoolOptions = new ChannelPoolOptions().maxCacheSize(maxChannelPoolSize)
                .subscriptionScheduler(VirtualTimeScheduler.create());
        lazyChannelPool = new LazyChannelPool(Mono.just(connection), channelPoolOptions);

        StepVerifier.withVirtualTime(() -> Mono.when(
                // 1#
                useChannelFromStartUntil(ofSeconds(3)),
                // 2#
                useChannelBetween(ofSeconds(1), ofSeconds(2)),
                // 3#
                useChannelBetween(ofSeconds(4), ofSeconds(5)))).expectSubscription().thenAwait(ofSeconds(5))
                .verifyComplete();
        // Expectations, numbers on the left mean elapsed time in seconds
        // 0 -> 1# creates channel1
        // 1 -> 2# creates channel2
        // 2 -> 2# releases channel2, 2# adds channel2 to pool
        // 3 -> 1# releases channel1, 1# closes channel1 (pool is full)
        // 4 -> 3# obtains channel2 from pool
        // 5 -> 3# releases channel2, 2# adds channel2 to pool

        verifyBasicPublishOnce(channel1);
        verifyBasicPublish(channel2, 2);
        verify(channel1).close();
        verify(channel2, never()).close();

        lazyChannelPool.close();
        verify(channel2).close();
    }

    private Mono<Void> useChannelFromStartUntil(Duration until) {
        return useChannelBetween(Duration.ZERO, until);
    }

    private Mono<Void> useChannelBetween(Duration from, Duration to) {
        return Mono.delay(from).then(lazyChannelPool.getChannelMono())
                .flatMap(channel -> Mono.just(1).doOnNext(i -> {
                    try {
                        channel.basicPublish("", "", null, "".getBytes());
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }).delayElement(to.minus(from)).doFinally(
                        signalType -> lazyChannelPool.getChannelCloseHandler().accept(signalType, channel)))
                .then();
    }

    private void verifyBasicPublishNever(Channel channel) throws Exception {
        verifyBasicPublish(channel, 0);
    }

    private void verifyBasicPublishOnce(Channel channel) throws Exception {
        verifyBasicPublish(channel, 1);
    }

    private void verifyBasicPublish(Channel channel, int times) throws Exception {
        verify(channel, times(times)).basicPublish(anyString(), anyString(), nullable(AMQP.BasicProperties.class),
                any(byte[].class));
    }

    private Channel channel(int channelNumber) {
        Channel channel = mock(Channel.class);
        when(channel.getChannelNumber()).thenReturn(channelNumber);
        when(channel.isOpen()).thenReturn(true);
        when(channel.getConnection()).thenReturn(connection);
        return channel;
    }
}