All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.turbospaces.boot.test.MockUtil Maven / Gradle / Ivy

package com.turbospaces.boot.test;

import static org.mockito.Mockito.mock;

import java.net.URI;
import java.time.Duration;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.function.Consumer;

import org.mockito.Mockito;
import org.mockito.verification.VerificationMode;

import com.google.common.io.ByteSource;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.protobuf.Message;
import com.google.protobuf.Timestamp;
import com.turbospaces.api.ServiceApi;
import com.turbospaces.api.Topic;
import com.turbospaces.api.facade.RequestWrapperFacade;
import com.turbospaces.api.facade.ResponseStatusFacade;
import com.turbospaces.api.facade.ResponseWrapperFacade;
import com.turbospaces.boot.Bootstrap;
import com.turbospaces.cfg.ApplicationConfig;
import com.turbospaces.common.PlatformUtil;
import com.turbospaces.dispatch.EmbeddedTransactionalRequest;
import com.turbospaces.dispatch.RequestQueuePostSpec;
import com.turbospaces.dispatch.TransactionalRequest;
import com.turbospaces.executor.WorkUnit;
import com.turbospaces.mdc.ContextPropagator;
import com.turbospaces.rpc.DefaultApiResponse;
import com.turbospaces.rpc.QueuePostTemplate;
import com.turbospaces.rpc.RequestReplyTimeout;

import api.v1.ApiFactory;
import io.cloudevents.core.builder.CloudEventBuilder;
import io.netty.util.AsciiString;
import io.vavr.CheckedConsumer;

@SuppressWarnings("unchecked")
public class MockUtil {
    private final Timestamp foo = Timestamp.getDefaultInstance();
    private final Bootstrap bootstrap = Mockito.mock(Bootstrap.class);
    private final ApiFactory apiFactory;
    private final Topic topic = new Topic() {
        @Override
        public AsciiString name() {
            return AsciiString.cached("embedded");
        }
        @Override
        public void configure(ApplicationConfig cfg) {

        }
    };

    public MockUtil(ApiFactory apiFactory) {
        this.apiFactory = Objects.requireNonNull(apiFactory);
    }
    public  MockCall mockServiceCall(V service, CheckedConsumer action, T resp) throws Throwable {
        RequestQueuePostSpec spec = (RequestQueuePostSpec) RequestQueuePostSpec.newBuilder(foo).setTopic(topic).build();
        Duration timeout = Duration.ofSeconds(30);
        RequestWrapperFacade requestWrapper = apiFactory.requestMapper().pack(
                spec,
                new ContextPropagator() {
                    @Override
                    public void injectContext(api.v1.Headers.Builder into) {

                    }
                }, timeout);
        var eventTemplate = CloudEventBuilder.v1().withSource(URI.create(PlatformUtil.randomUUID().toString()));
        ResponseWrapperFacade replyWrapper = apiFactory.requestMapper().toReply(
                eventTemplate,
                requestWrapper.headers(),
                resp,
                api.v1.CacheControl.getDefaultInstance());
        ListenableFuture completable = Futures.immediateFuture(replyWrapper);
        DefaultApiResponse apiResponse = new DefaultApiResponse(
                completable,
                apiFactory,
                (Class) resp.getClass(),
                requestWrapper);
        apiResponse.setBootstrap(bootstrap);

        var mock = Mockito.doReturn(apiResponse).when(service);
        action.accept(mock);
        return new MockCall(mode -> verifyServiceCall(service, action, mode));
    }

    public  MockCall mockServiceCall(V api, CheckedConsumer action, T resp, T... nextResp) throws Throwable {
        RequestQueuePostSpec spec = (RequestQueuePostSpec) RequestQueuePostSpec.newBuilder(foo).setTopic(topic).build();
        Duration timeout = Duration.ofSeconds(30);

        RequestWrapperFacade requestWrapper = apiFactory.requestMapper().pack(
                spec,
                new ContextPropagator() {
                    @Override
                    public void injectContext(api.v1.Headers.Builder into) {

                    }
                },
                timeout);

        var mock = Mockito.doReturn(toApiResponse(resp, requestWrapper), Arrays.stream(nextResp).map(r -> toApiResponse(r, requestWrapper)).toArray())
                .when(api);
        action.accept(mock);
        return new MockCall(mode -> verifyServiceCall(api, action, mode));
    }

    public  MockCall mockServiceCall(V api, CheckedConsumer action, List> responses) throws Throwable {
        var mock = Mockito.doReturn(responses.get(0), responses.subList(1, responses.size()).toArray()).when(api);
        action.accept(mock);
        return new MockCall(mode -> verifyServiceCall(api, action, mode));
    }

    private  DefaultApiResponse toApiResponse(T resp, RequestWrapperFacade requestWrapper) {
        var eventTemplate = CloudEventBuilder.v1().withSource(URI.create(PlatformUtil.randomUUID().toString()));
        ResponseWrapperFacade replyWrapper = apiFactory.requestMapper().toReply(
                eventTemplate,
                requestWrapper.headers(),
                resp,
                api.v1.CacheControl.getDefaultInstance());
        ListenableFuture completable = Futures.immediateFuture(replyWrapper);
        var toReturn = new DefaultApiResponse(
                completable,
                apiFactory,
                (Class) resp.getClass(),
                requestWrapper);
        toReturn.setBootstrap(bootstrap);
        return toReturn;
    }

    public  DefaultApiResponse toApiResponse(T resp, ResponseStatusFacade status) {
        RequestQueuePostSpec spec = (RequestQueuePostSpec) RequestQueuePostSpec.newBuilder(foo).setTopic(topic).build();
        Duration timeout = Duration.ofSeconds(30);
        RequestWrapperFacade requestWrapper = apiFactory.requestMapper().pack(
                spec,
                new ContextPropagator() {
                    @Override
                    public void injectContext(api.v1.Headers.Builder into) {

                    }
                },
                timeout);

        var eventTemplate = CloudEventBuilder.v1().withSource(URI.create(PlatformUtil.randomUUID().toString()));
        ResponseWrapperFacade replyWrapper = apiFactory.requestMapper().toReply(eventTemplate, requestWrapper.headers(), resp, status);
        ListenableFuture completable = Futures.immediateFuture(replyWrapper);

        var toReturn = new DefaultApiResponse(
                completable,
                apiFactory,
                (Class) resp.getClass(),
                requestWrapper);
        toReturn.setBootstrap(bootstrap);
        return toReturn;
    }

    public  MockCall mockServiceCallWithTimeout(V api, CheckedConsumer action, Class respClass) throws Throwable {
        Duration timeout = Duration.ofSeconds(30);
        RequestWrapperFacade requestWrapper = apiFactory.requestMapper().pack(
                (RequestQueuePostSpec) RequestQueuePostSpec.newBuilder(foo).setTopic(topic).build(),
                new ContextPropagator() {
                    @Override
                    public void injectContext(api.v1.Headers.Builder into) {

                    }
                }, timeout);
        String messageId = requestWrapper.headers().getMessageId();
        RequestReplyTimeout replyTimeout = new RequestReplyTimeout(timeout, messageId, false);
        ResponseWrapperFacade replyWrapper = apiFactory.responseMapper().toTimeoutReplyWithoutBody(replyTimeout);
        ListenableFuture completable = Futures.immediateFuture(replyWrapper);
        DefaultApiResponse apiResponse = new DefaultApiResponse(
                completable,
                apiFactory,
                respClass,
                requestWrapper);
        apiResponse.setBootstrap(bootstrap);

        var mock = Mockito.doReturn(apiResponse).when(api);
        action.accept(mock);
        return new MockCall(mode -> {
            try {
                verifyServiceCall(api, action, mode);
            } catch (Throwable err) {}
        });
    }
    public  MockCall mockServiceCall(
            V api,
            CheckedConsumer action,
            T respPrototype,
            Throwable err) throws Throwable {
        Duration timeout = Duration.ofSeconds(30);
        RequestWrapperFacade requestWrapper = apiFactory.requestMapper().pack(
                (RequestQueuePostSpec) RequestQueuePostSpec.newBuilder(foo).setTopic(topic).build(),
                new ContextPropagator() {
                    @Override
                    public void injectContext(api.v1.Headers.Builder into) {

                    }
                }, timeout);

        var eventTemplate = CloudEventBuilder.v1().withSource(URI.create(PlatformUtil.randomUUID().toString()));
        ResponseWrapperFacade replyWrapper = apiFactory.requestMapper().toExceptionalReply(eventTemplate, requestWrapper.headers(), respPrototype, err);
        ListenableFuture completable = Futures.immediateFuture(replyWrapper);
        DefaultApiResponse apiResponse = new DefaultApiResponse(
                completable,
                apiFactory,
                (Class) respPrototype.getClass(),
                requestWrapper);
        apiResponse.setBootstrap(bootstrap);

        var mock = Mockito.doReturn(apiResponse).when(api);
        action.accept(mock);
        return new MockCall(mode -> verifyServiceCall(api, action, mode));
    }
    public  MockCall mockServiceCall(
            V api,
            CheckedConsumer action,
            T resp,
            ResponseStatusFacade err) throws Throwable {
        RequestQueuePostSpec spec = (RequestQueuePostSpec) RequestQueuePostSpec.newBuilder(foo).setTopic(topic).build();
        Duration timeout = Duration.ofSeconds(30);

        RequestWrapperFacade requestWrapper = apiFactory.requestMapper().pack(
                spec,
                new ContextPropagator() {
                    @Override
                    public void injectContext(api.v1.Headers.Builder into) {

                    }
                }, timeout);

        var eventTemplate = CloudEventBuilder.v1().withSource(URI.create(PlatformUtil.randomUUID().toString()));
        ResponseWrapperFacade replyWrapper = apiFactory.requestMapper().toReply(eventTemplate, requestWrapper.headers(), resp, err);
        ListenableFuture completable = Futures.immediateFuture(replyWrapper);
        DefaultApiResponse apiResponse = new DefaultApiResponse(
                completable,
                apiFactory,
                (Class) resp.getClass(),
                requestWrapper);
        apiResponse.setBootstrap(bootstrap);

        var mock = Mockito.doReturn(apiResponse).when(api);
        action.accept(mock);
        return new MockCall(mode -> verifyServiceCall(api, action, mode));
    }
    public MockCall mockSinkEvent(QueuePostTemplate postTemplate, Consumer> action) {
        //
        // ~ do not confuse with guava's (it might cause crazy miss-leading errors)
        //
        var mock = Mockito.doReturn(mock(CompletableFuture.class)).when(postTemplate);
        action.accept(mock);
        return new MockCall(mode -> verifyPostCall(postTemplate, action, mode));
    }
    private static void verifyPostCall(QueuePostTemplate postTemplate, Consumer> action, VerificationMode verification) {
        QueuePostTemplate mock = Mockito.verify(postTemplate, verification);
        action.accept(mock);
    }
    private static  void verifyServiceCall(V api, CheckedConsumer action, VerificationMode verification) throws Throwable {
        V mock = Mockito.verify(api, verification);
        action.accept(mock);
    }
    public  TransactionalRequest toTransactionalRequest(
            Class reqType,
            REQ req,
            RESP resp) {
        long now = System.currentTimeMillis();
        RequestWrapperFacade requestWrapper = apiFactory.requestMapper().pack(
                (RequestQueuePostSpec) RequestQueuePostSpec.newBuilder(req).setTopic(topic).build(),
                new ContextPropagator() {
                    @Override
                    public void injectContext(api.v1.Headers.Builder into) {

                    }
                }, Duration.ofSeconds(30));

        return new EmbeddedTransactionalRequest<>(reqType, resp, new WorkUnit() {
            @Override
            public String topic() {
                return topic.name().toString();
            }
            @Override
            public long timestamp() {
                return now;
            }
            @Override
            public byte[] key() {
                return null;
            }
            @Override
            public ByteSource value() {
                return ByteSource.empty();
            }
        }, requestWrapper, new CountDownLatch(1));
    }
    public  TransactionalRequest toTransactionalRequest(
            Class reqType,
            REQ req,
            RESP resp,
            AsciiString hash) {
        long now = System.currentTimeMillis();
        RequestWrapperFacade requestWrapper = apiFactory.requestMapper().pack(
                (RequestQueuePostSpec) RequestQueuePostSpec.newBuilder(req).setTopic(topic).setRoutingKey(hash).build(),
                new ContextPropagator() {
                    @Override
                    public void injectContext(api.v1.Headers.Builder into) {

                    }
                }, Duration.ofSeconds(30));

        return new EmbeddedTransactionalRequest<>(reqType, resp, new WorkUnit() {
            @Override
            public String topic() {
                return topic.name().toString();
            }
            @Override
            public long timestamp() {
                return now;
            }
            @Override
            public byte[] key() {
                return hash.toString().getBytes();
            }
            @Override
            public ByteSource value() {
                return ByteSource.empty();
            }
        }, requestWrapper, new CountDownLatch(1));
    }

    public static class MockCall {
        private final CheckedConsumer verifyCallback;

        public MockCall(CheckedConsumer verifyCallback) {
            this.verifyCallback = Objects.requireNonNull(verifyCallback);
        }
        public void verify() throws Throwable {
            verifyCallback.accept(Mockito.times(1));
        }
        public void verify(VerificationMode verificationMode) throws Throwable {
            verifyCallback.accept(verificationMode);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy