@Override
    protected Mono<Void> doExecute(final ServerWebExchange exchange, final ShenyuPluginChain chain, final SelectorData selector, final RuleData rule) {
        final String param = exchange.getAttribute(Constants.PARAM_TRANSFORM);
        ShenyuContext shenyuContext = exchange.getAttribute(Constants.CONTEXT);
        assert shenyuContext != null;
        MetaData metaData = exchange.getAttribute(Constants.META_DATA);

        if (!checkMetaData(metaData)) {
            LOG.error(" path is :{}, meta data have error.... {}", shenyuContext.getPath(), metaData);
            exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
            Object error = ShenyuResultWrap.error(exchange, ShenyuResultEnum.META_DATA_ERROR);
            return WebFluxResultUtils.result(exchange, error);
        }
        assert metaData != null;
        if (StringUtils.isNoneBlank(metaData.getParameterTypes()) && StringUtils.isBlank(param)) {
            exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
            Object error = ShenyuResultWrap.error(exchange, ShenyuResultEnum.GRPC_HAVE_BODY_PARAM);
            return WebFluxResultUtils.result(exchange, error);
        }

        final ShenyuGrpcClient client = GrpcClientCache.getGrpcClient(selector.getId());
        if (Objects.isNull(client)) {
            exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
            Object error = ShenyuResultWrap.error(exchange, ShenyuResultEnum.GRPC_CLIENT_NULL);
            return WebFluxResultUtils.result(exchange, error);
        }
        // load balance context
        Context.current().withValue(GrpcConstants.GRPC_SELECTOR_ID, selector.getId()).attach();
        Context.current().withValue(GrpcConstants.GRPC_RULE_ID, rule.getId()).attach();
        Context.current().withValue(GrpcConstants.GRPC_REMOTE_ADDRESS,
                Objects.requireNonNull(exchange.getRequest().getRemoteAddress()).getAddress().getHostAddress()).attach();

        GrpcExtInfo extInfo = GsonUtils.getGson().fromJson(metaData.getRpcExt(), GrpcExtInfo.class);
        CallOptions callOptions = CallOptions.DEFAULT.withDeadlineAfter(extInfo.timeout, TimeUnit.MILLISECONDS);
        Map<String, Map<String, String>> rpcContext = exchange.getAttribute(Constants.GENERAL_CONTEXT);
        Optional.ofNullable(rpcContext).map(context -> context.get(PluginEnum.GRPC.getName())).ifPresent(
            context -> Context.current().withValue(RPC_CONTEXT_KEY, context).attach());
        CompletableFuture<ShenyuGrpcResponse> result = client.call(metaData, callOptions, param, extInfo.methodType);
        Context.current().detach(Context.ROOT);

        return Mono.fromFuture(result.thenApply(ret -> {
            exchange.getAttributes().put(Constants.RPC_RESULT, ret.getResults());
            exchange.getAttributes().put(Constants.CLIENT_RESPONSE_RESULT_TYPE, ResultEnum.SUCCESS.getName());
            return ret;
        })).onErrorMap(ShenyuException::new).then(chain.execute(exchange));
    }
@Test
    @SuppressWarnings("all")
    public void testDoExecute() throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
        ServerWebExchange exchange = getServerWebExchange();
        exchange.getAttributes().put(Constants.PARAM_TRANSFORM, "{message:1}");
        exchange.getAttributes().put(Constants.META_DATA, getMetaData());

        Class<?> grpcClientCacheClass = Class.forName("org.apache.shenyu.plugin.grpc.cache.GrpcClientCache");
        Field clientCacheField = grpcClientCacheClass.getDeclaredField("CLIENT_CACHE");
        clientCacheField.setAccessible(true);
        Map<String, ShenyuGrpcClient> clientCacheMap = (Map<String, ShenyuGrpcClient>) clientCacheField.get(grpcClientCacheClass);
        ShenyuGrpcClient mockClient = mock(ShenyuGrpcClient.class);
        ShenyuGrpcResponse response = new ShenyuGrpcResponse();
        response.getResults().add("success");
        when(mockClient.call(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any()))
                .thenReturn(CompletableFuture.completedFuture(response));
        clientCacheMap.put("/grpc", mockClient);

        when(chain.execute(Mockito.any())).thenReturn(Mono.empty());
        RuleData data = mock(RuleData.class);
        StepVerifier.create(grpcPlugin.doExecute(exchange, chain, selector, data)).expectSubscription().verifyComplete();
    }