diff --git a/handlers/handler-flowcontrol-qps/pom.xml b/handlers/handler-flowcontrol-qps/pom.xml index e9c10bdd13..86a3943ec4 100644 --- a/handlers/handler-flowcontrol-qps/pom.xml +++ b/handlers/handler-flowcontrol-qps/pom.xml @@ -16,29 +16,34 @@ --> - 4.0.0 - - org.apache.servicecomb - handlers - 1.0.0-m1 - - handler-flowcontrol-qps - Java Chassis::Handlers::Flow Control QPS - - - org.apache.servicecomb - java-chassis-core - - - org.slf4j - slf4j-log4j12 - test - - - log4j - log4j - test - - + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + + org.apache.servicecomb + handlers + 1.0.0-m1 + + handler-flowcontrol-qps + Java Chassis::Handlers::Flow Control QPS + + + org.apache.servicecomb + java-chassis-core + + + org.slf4j + slf4j-log4j12 + test + + + log4j + log4j + test + + + org.apache.servicecomb + foundation-test-scaffolding + test + + diff --git a/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/ConsumerQpsControllerManager.java b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/ConsumerQpsControllerManager.java deleted file mode 100644 index 076df492d9..0000000000 --- a/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/ConsumerQpsControllerManager.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * 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.servicecomb.qps; - -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.foundation.common.AbstractObjectManager; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.netflix.config.DynamicProperty; - -/** - * 以microservice.schema.operation为key - * 如果配置只到microservice级别,那么该microservice中所有的key都关联到同一个qpsController实例 - * 然后schema、operation级别有独立配置的,单独关联自己的qpsController实例 - * - * schema级独立的qpsController统计时,并不会导致microservice级别的统计也改变,operation级别规则也相同 - * 即:统计只在qpsController实例内部生效,不会产生实例间的关联 - * - */ -public class ConsumerQpsControllerManager extends AbstractObjectManager { - private static final Logger LOGGER = LoggerFactory.getLogger(ConsumerQpsControllerManager.class); - // 最终使用的QpsController实例,实际都是从下面的map中引用出来的,不会独立创建 - - // 3种类型的key都保存在这里,不存在冲突 - // microservice - // microservice.schema - // microservice.schema.operation - private Map qpsControllerMap = new ConcurrentHashMap<>(); - - // 避免重复watch - // 只会在create流程中调用,是有锁保护的,不必考虑多线程并发 - private Set watchedKeySet = new HashSet<>(); - - @Override - protected String getKey(OperationMeta operationMeta) { - return operationMeta.getMicroserviceQualifiedName(); - } - - private QpsController initQpsLimit(String key, Integer qpsLimit) { - if (qpsLimit == null) { - return null; - } - - LOGGER.info("qpsLimit of {} init as {}", key, qpsLimit); - - QpsController qpsController = new QpsController(key, qpsLimit); - qpsControllerMap.put(key, qpsController); - return qpsController; - } - - private QpsController updateQpsLimit(String key, Integer qpsLimit) { - QpsController qpsController = qpsControllerMap.get(key); - if (qpsController == null && qpsLimit != null) { - qpsController = new QpsController(key, qpsLimit); - qpsControllerMap.put(key, qpsController); - } - - if (qpsController != null) { - LOGGER.info("qpsLimit of {} changed from {} to {}", key, qpsController.getQpsLimit(), qpsLimit); - - qpsController.setQpsLimit(qpsLimit); - } - - return qpsController; - } - - private QpsController findReference(String key) { - QpsController qpsController = qpsControllerMap.get(key); - if (qpsController == null) { - return null; - } - - if (qpsController.getQpsLimit() == null) { - return null; - } - - return qpsController; - } - - private QpsController findReference(OperationMeta operationMeta) { - QpsController qpsController = findReference(operationMeta.getMicroserviceQualifiedName()); - if (qpsController != null) { - return qpsController; - } - - qpsController = findReference(operationMeta.getSchemaMeta().getMicroserviceQualifiedName()); - if (qpsController != null) { - return qpsController; - } - - qpsController = findReference(operationMeta.getMicroserviceName()); - if (qpsController != null) { - return qpsController; - } - - return initQpsLimit(operationMeta.getMicroserviceName(), Integer.MAX_VALUE); - } - - @Override - protected QpsController create(OperationMeta operationMeta) { - // create在父类中是加了锁的,不存在并发的场景 - initConfig(operationMeta, operationMeta.getMicroserviceQualifiedName()); - initConfig(operationMeta, operationMeta.getSchemaMeta().getMicroserviceQualifiedName()); - initConfig(operationMeta, operationMeta.getMicroserviceName()); - - return findReference(operationMeta); - } - - private void initConfig(OperationMeta operationMeta, String key) { - if (watchedKeySet.contains(key)) { - return; - } - - watchedKeySet.add(key); - - String configKey = Config.CONSUMER_LIMIT_KEY_PREFIX + key; - DynamicProperty property = DynamicProperty.getInstance(configKey); - initQpsLimit(key, getIntegerLimitProperty(property)); - - property.addCallback(() -> { - updateQpsLimit(key, getIntegerLimitProperty(property)); - QpsController qpsController = findReference(operationMeta); - - objMap.put(operationMeta.getMicroserviceQualifiedName(), qpsController); - }); - } - - private Integer getIntegerLimitProperty(DynamicProperty property) { - try { - return property.getInteger(); - } catch (IllegalArgumentException e) { - LOGGER.error(e.getMessage()); - return null; - } - } -} diff --git a/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/ConsumerQpsFlowControlHandler.java b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/ConsumerQpsFlowControlHandler.java index b1fd2a669c..101babc851 100644 --- a/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/ConsumerQpsFlowControlHandler.java +++ b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/ConsumerQpsFlowControlHandler.java @@ -19,18 +19,17 @@ import org.apache.servicecomb.core.Handler; import org.apache.servicecomb.core.Invocation; -import org.apache.servicecomb.core.definition.OperationMeta; import org.apache.servicecomb.swagger.invocation.AsyncResponse; import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; import org.apache.servicecomb.swagger.invocation.exception.InvocationException; /** - * consumer端针对调用目标的qps控制 - * 支持microservice、schema、operation三个级别的控制 - * + * For qps flow control on consumer side. + * Support 3 levels of microservice/schema/operation. */ public class ConsumerQpsFlowControlHandler implements Handler { - private ConsumerQpsControllerManager qpsControllerMgr = new ConsumerQpsControllerManager(); + static final QpsControllerManager qpsControllerMgr = new QpsControllerManager() + .setConfigKeyPrefix(Config.CONSUMER_LIMIT_KEY_PREFIX); @Override public void handle(Invocation invocation, AsyncResponse asyncResp) throws Exception { @@ -39,10 +38,10 @@ public void handle(Invocation invocation, AsyncResponse asyncResp) throws Except return; } - OperationMeta operationMeta = invocation.getOperationMeta(); - QpsController qpsController = qpsControllerMgr.getOrCreate(operationMeta); + QpsController qpsController = qpsControllerMgr.getOrCreate( + invocation.getOperationMeta().getMicroserviceQualifiedName()); if (qpsController.isLimitNewRequest()) { - // 429 + // return http status 429 CommonExceptionData errorData = new CommonExceptionData("rejected by qps flowcontrol"); asyncResp.consumerFail( new InvocationException(QpsConst.TOO_MANY_REQUESTS_STATUS, errorData)); diff --git a/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/ProviderQpsControllerManager.java b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/ProviderQpsControllerManager.java deleted file mode 100644 index d8d6c76ac5..0000000000 --- a/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/ProviderQpsControllerManager.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * 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.servicecomb.qps; - -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -import org.apache.servicecomb.foundation.common.AbstractObjectManager; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.netflix.config.DynamicProperty; - -public class ProviderQpsControllerManager - extends AbstractObjectManager { - private static final Logger LOGGER = LoggerFactory.getLogger(ProviderQpsControllerManager.class); - - private Map qpsControllerMap = new ConcurrentHashMap<>(); - - // 避免重复watch - // 只会在create流程中调用,是有锁保护的,不必考虑多线程并发 - private Set watchedKeySet = new HashSet<>(); - - private QpsController globalQpsController = null; - - @Override - protected String getKey(String microServiceName) { - return microServiceName; - } - - @Override - public QpsController getOrCreate(String keyOwner) { - if (keyOwner == null) { - if (globalQpsController == null) { - synchronized (lockObj) { - if (globalQpsController == null) { - DynamicProperty property = - DynamicProperty.getInstance(Config.PROVIDER_LIMIT_KEY_GLOBAL); - globalQpsController = new QpsController(keyOwner, getIntegerLimitProperty(property)); - property.addCallback(() -> { - globalQpsController.setQpsLimit(getIntegerLimitProperty(property)); - }); - } - } - } - return globalQpsController; - } else { - return super.getOrCreate(keyOwner); - } - } - - private QpsController initQpsLimit(String key, Integer qpsLimit) { - if (qpsLimit == null) { - qpsLimit = null; - } - - LOGGER.info("qpsLimit of {} init as {}", key, qpsLimit); - - QpsController qpsController = new QpsController(key, qpsLimit); - qpsControllerMap.put(key, qpsController); - return qpsController; - } - - private QpsController updateQpsLimit(String key, Integer qpsLimit) { - QpsController qpsController = qpsControllerMap.get(key); - if (qpsController == null && qpsLimit != null) { - qpsController = new QpsController(key, qpsLimit); - qpsControllerMap.put(key, qpsController); - } - - if (qpsController != null) { - LOGGER.info("qpsLimit of {} changed from {} to {}", - key, - qpsController.getQpsLimit(), - qpsLimit); - - qpsController.setQpsLimit(qpsLimit); - } - - return qpsController; - } - - private QpsController findReference(String key) { - QpsController qpsController = qpsControllerMap.get(key); - if (qpsController == null) { - return initQpsLimit(key, Integer.MAX_VALUE); - } - return qpsController; - } - - @Override - protected QpsController create(String microServiceName) { - // create在父类中是加了锁的,不存在并发的场景 - initConfig(microServiceName); - - return findReference(microServiceName); - } - - private void initConfig(String key) { - if (watchedKeySet.contains(key)) { - return; - } - - watchedKeySet.add(key); - - String configKey = Config.PROVIDER_LIMIT_KEY_PREFIX + key; - DynamicProperty property = DynamicProperty.getInstance(configKey); - initQpsLimit(key, getIntegerLimitProperty(property)); - - property.addCallback(() -> { - updateQpsLimit(key, getIntegerLimitProperty(property)); - QpsController qpsController = findReference(key); - - objMap.put(key, qpsController); - }); - } - - private Integer getIntegerLimitProperty(DynamicProperty property) { - try { - return property.getInteger(); - } catch (IllegalArgumentException e) { - LOGGER.error(e.getMessage()); - return null; - } - } -} diff --git a/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/ProviderQpsFlowControlHandler.java b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/ProviderQpsFlowControlHandler.java index 1cf669d812..b81581ff57 100644 --- a/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/ProviderQpsFlowControlHandler.java +++ b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/ProviderQpsFlowControlHandler.java @@ -23,9 +23,12 @@ import org.apache.servicecomb.swagger.invocation.AsyncResponse; import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData; import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.springframework.util.StringUtils; public class ProviderQpsFlowControlHandler implements Handler { - private ProviderQpsControllerManager qpsControllerMgr = new ProviderQpsControllerManager(); + static final QpsControllerManager qpsControllerMgr = new QpsControllerManager() + .setConfigKeyPrefix(Config.PROVIDER_LIMIT_KEY_PREFIX) + .setGlobalQpsController(Config.PROVIDER_LIMIT_KEY_GLOBAL); @Override public void handle(Invocation invocation, AsyncResponse asyncResp) throws Exception { @@ -34,16 +37,13 @@ public void handle(Invocation invocation, AsyncResponse asyncResp) throws Except return; } - String microServiceName = (String) invocation.getContext(Const.SRC_MICROSERVICE); - if (microServiceName != null && !microServiceName.isEmpty()) { - QpsController qpsController = qpsControllerMgr.getOrCreate(microServiceName); - if (isLimitNewRequest(qpsController, asyncResp)) { - return; - } - } - - QpsController globalQpsController = qpsControllerMgr.getOrCreate(null); - if (isLimitNewRequest(globalQpsController, asyncResp)) { + String microServiceName = invocation.getContext(Const.SRC_MICROSERVICE); + QpsController qpsController = + StringUtils.isEmpty(microServiceName) + ? qpsControllerMgr.getGlobalQpsController() + : qpsControllerMgr.getOrCreate(microServiceName + QpsControllerManager.SEPARATOR + + invocation.getOperationMeta().getSchemaQualifiedName()); + if (isLimitNewRequest(qpsController, asyncResp)) { return; } diff --git a/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/QpsControllerManager.java b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/QpsControllerManager.java new file mode 100644 index 0000000000..09a69ed07b --- /dev/null +++ b/handlers/handler-flowcontrol-qps/src/main/java/org/apache/servicecomb/qps/QpsControllerManager.java @@ -0,0 +1,175 @@ +/* + * 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.servicecomb.qps; + +import java.util.Map; +import java.util.Map.Entry; +import java.util.regex.Pattern; + +import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.netflix.config.DynamicProperty; + +public class QpsControllerManager { + private static final Logger LOGGER = LoggerFactory.getLogger(QpsControllerManager.class); + + private static final Pattern QUALIFIED_KEY_CHECKER = Pattern.compile("^[^.]+\\.[^.]+\\.[^.]+$"); + + /** + * Describe the relationship between configuration and qpsController. + */ + protected final Map configQpsControllerMap = new ConcurrentHashMapEx<>(); + + /** + * Describe the relationship between qualifiedKey(format is "microservice.schema.operation") and qpsController. + */ + protected final Map qualifiedNameControllerMap = new ConcurrentHashMapEx<>(); + + protected QpsController globalQpsController; + + public static final String SEPARATOR = "."; + + private String configKeyPrefix; + + public QpsController getOrCreate(String key) { + return qualifiedNameControllerMap.computeIfAbsent(key, this::create); + } + + /** + * Create relevant qpsLimit dynamicProperty and watch the configuration change. + * Search and return a valid qpsController. + */ + protected QpsController create(String qualifiedNameKey) { + if (!QUALIFIED_KEY_CHECKER.matcher(qualifiedNameKey).matches()) { + throw new IllegalArgumentException("Unexpected qualified name: [" + qualifiedNameKey + "]"); + } + // create "microservice" + createQpsControllerIfNotExist(qualifiedNameKey.substring(0, qualifiedNameKey.indexOf(SEPARATOR))); + // create "microservice.schema" + createQpsControllerIfNotExist(qualifiedNameKey.substring(0, qualifiedNameKey.lastIndexOf(SEPARATOR))); + // create "microservice.schema.operation" + createQpsControllerIfNotExist(qualifiedNameKey); + + return searchQpsController(qualifiedNameKey); + } + + /** + *

Use qualifiedNameKey to search {@link QpsController}. + * Firstly try to search "microservice.schema.operation". If no valid result found, then try "microservice.schema", + * and then "microservice" or global qpsController(If there is a global qpsController).

+ *

This method ensures that there is always an existing qpsController returned, as the relevant qpsController has + * been created and stored in {@link #create(String)}

+ * + * @param qualifiedNameKey qualifiedNameKey in {@link #qualifiedNameControllerMap} + * @return a qps controller, lower level controllers with valid qpsLimit have priority. + */ + protected QpsController searchQpsController(String qualifiedNameKey) { + QpsController qpsController = configQpsControllerMap.get(qualifiedNameKey); + if (isValidQpsController(qpsController)) { + return qpsController; + } + + int index = qualifiedNameKey.lastIndexOf(SEPARATOR); + while (index > 0) { + qpsController = configQpsControllerMap.get(qualifiedNameKey.substring(0, index)); + if (isValidQpsController(qpsController)) { + return qpsController; + } + + index = qualifiedNameKey.lastIndexOf(SEPARATOR, index - 1); + } + + if (isValidQpsController(qpsController)) { + return qpsController; + } + + if (null != globalQpsController) { + return globalQpsController; + } + + // if null is returned, maybe the operation qps controller is not initiated correctly. + // getOrCreateQpsController() should be invoked before. + return qpsController; + } + + private boolean keyMatch(String configKey, Entry controllerEntry) { + return controllerEntry.getKey().equals(configKey) + || controllerEntry.getKey().startsWith(configKey + SEPARATOR); + } + + private boolean isValidQpsController(QpsController qpsController) { + return null != qpsController && null != qpsController.getQpsLimit(); + } + + private void createQpsControllerIfNotExist(String configKey) { + if (configQpsControllerMap.keySet().contains(configKey)) { + return; + } + + LOGGER.info("Create qpsController, configKey = [{}]", configKey); + DynamicProperty property = getDynamicProperty(configKey); + QpsController qpsController = new QpsController(configKey, property.getInteger()); + + configQpsControllerMap.put(configKey, qpsController); + + property.addCallback(() -> { + qpsController.setQpsLimit(property.getInteger()); + LOGGER.info("Qps limit updated, configKey = [{}], value = [{}]", configKey, property.getString()); + updateObjMap(configKey); + }); + } + + protected void updateObjMap(String configKey) { + for (Entry controllerEntry : qualifiedNameControllerMap.entrySet()) { + if (keyMatch(configKey, controllerEntry)) { + QpsController qpsController = searchQpsController(controllerEntry.getKey()); + controllerEntry.setValue(qpsController); + LOGGER.info("QpsController updated, operationId = [{}], configKey = [{}], qpsLimit = [{}]", + controllerEntry.getKey(), qpsController.getKey(), qpsController.getQpsLimit()); + } + } + } + + public QpsControllerManager setConfigKeyPrefix(String configKeyPrefix) { + this.configKeyPrefix = configKeyPrefix; + return this; + } + + public QpsControllerManager setGlobalQpsController(String globalConfigKey) { + DynamicProperty globalQpsProperty = DynamicProperty.getInstance(globalConfigKey); + QpsController qpsController = new QpsController(globalConfigKey, globalQpsProperty.getInteger()); + + globalQpsProperty.addCallback(() -> { + qpsController.setQpsLimit(globalQpsProperty.getInteger()); + LOGGER.info("Global qps limit update, value = [{}]", globalQpsProperty.getInteger()); + }); + + this.globalQpsController = qpsController; + return this; + } + + public QpsController getGlobalQpsController() { + return globalQpsController; + } + + protected DynamicProperty getDynamicProperty(String configKey) { + return DynamicProperty.getInstance(configKeyPrefix + configKey); + } +} diff --git a/handlers/handler-flowcontrol-qps/src/test/java/org/apache/servicecomb/qps/QpsControllerManagerTest.java b/handlers/handler-flowcontrol-qps/src/test/java/org/apache/servicecomb/qps/QpsControllerManagerTest.java new file mode 100644 index 0000000000..1837ff2972 --- /dev/null +++ b/handlers/handler-flowcontrol-qps/src/test/java/org/apache/servicecomb/qps/QpsControllerManagerTest.java @@ -0,0 +1,258 @@ +/* + * 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.servicecomb.qps; + +import java.util.Map; + +import org.apache.servicecomb.core.Invocation; +import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.core.definition.SchemaMeta; +import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import mockit.Deencapsulation; + +public class QpsControllerManagerTest { + + @Before + public void beforeTest() { + ArchaiusUtils.resetConfig(); + } + + @After + public void afterTest() { + ArchaiusUtils.resetConfig(); + } + + @Test + public void testGetOrCreate() { + QpsControllerManager testQpsControllerManager = new QpsControllerManager() + .setConfigKeyPrefix(Config.CONSUMER_LIMIT_KEY_PREFIX); + initTestQpsControllerManager(testQpsControllerManager); + + // pojo + setConfigWithDefaultPrefix("pojo", 100); + QpsController qpsController = testQpsControllerManager.getOrCreate("pojo.server.test"); + Assert.assertEquals("pojo", qpsController.getKey()); + Assert.assertTrue(100 == qpsController.getQpsLimit()); + qpsController = testQpsControllerManager.getOrCreate("pojo2.server.test"); + Assert.assertEquals("pojo2", qpsController.getKey()); + Assert.assertNull(qpsController.getQpsLimit()); + qpsController = testQpsControllerManager.getOrCreate("poj.server.test"); + Assert.assertEquals("poj", qpsController.getKey()); + Assert.assertNull(qpsController.getQpsLimit()); + + testGetOrCreateCommon(testQpsControllerManager); + } + + @Test + public void testGetOrCreateWithGlobalConfig() { + QpsControllerManager testQpsControllerManager = new QpsControllerManager() + .setGlobalQpsController(Config.PROVIDER_LIMIT_KEY_GLOBAL) + .setConfigKeyPrefix(Config.CONSUMER_LIMIT_KEY_PREFIX); + + // global + setConfig(Config.PROVIDER_LIMIT_KEY_GLOBAL, 50); + QpsController qpsController = testQpsControllerManager.getOrCreate("pojo.server.test"); + Assert.assertEquals(Config.PROVIDER_LIMIT_KEY_GLOBAL, qpsController.getKey()); + Assert.assertTrue(50 == qpsController.getQpsLimit()); + qpsController = testQpsControllerManager.getOrCreate("pojo2.server.test"); + Assert.assertEquals(Config.PROVIDER_LIMIT_KEY_GLOBAL, qpsController.getKey()); + Assert.assertTrue(50 == qpsController.getQpsLimit()); + qpsController = testQpsControllerManager.getOrCreate("poj.server.test"); + Assert.assertEquals(Config.PROVIDER_LIMIT_KEY_GLOBAL, qpsController.getKey()); + Assert.assertTrue(50 == qpsController.getQpsLimit()); + + // pojo + setConfigWithDefaultPrefix("pojo", 100); + qpsController = testQpsControllerManager.getOrCreate("pojo.server.test"); + Assert.assertEquals("pojo", qpsController.getKey()); + Assert.assertTrue(100 == qpsController.getQpsLimit()); + qpsController = testQpsControllerManager.getOrCreate("pojo2.server.test"); + Assert.assertEquals(Config.PROVIDER_LIMIT_KEY_GLOBAL, qpsController.getKey()); + Assert.assertTrue(50 == qpsController.getQpsLimit()); + qpsController = testQpsControllerManager.getOrCreate("poj.server.test"); + Assert.assertEquals(Config.PROVIDER_LIMIT_KEY_GLOBAL, qpsController.getKey()); + Assert.assertTrue(50 == qpsController.getQpsLimit()); + + testGetOrCreateCommon(testQpsControllerManager); + } + + @Test + public void testQualifiedNameKey() { + QpsControllerManager qpsControllerManager = new QpsControllerManager(); + QpsController qpsController = qpsControllerManager.getOrCreate("service.schema.opr"); + Assert.assertEquals("service", qpsController.getKey()); + Assert.assertNull(qpsController.getQpsLimit()); + + qpsController = qpsControllerManager.getOrCreate("test_service.test_schema.test_opr"); + Assert.assertEquals("test_service", qpsController.getKey()); + Assert.assertNull(qpsController.getQpsLimit()); + + qpsController = qpsControllerManager.getOrCreate("test-service.test-schema.test-opr"); + Assert.assertEquals("test-service", qpsController.getKey()); + Assert.assertNull(qpsController.getQpsLimit()); + + Exception exception = null; + try { + qpsControllerManager.getOrCreate("svc.schema.opr.tail"); + } catch (Exception e) { + exception = e; + } + Assert.assertNotNull(exception); + Assert.assertEquals(IllegalArgumentException.class, exception.getClass()); + Assert.assertEquals("Unexpected qualified name: [svc.schema.opr.tail]", exception.getMessage()); + + try { + qpsControllerManager.getOrCreate("svc.schema"); + } catch (Exception e) { + exception = e; + } + Assert.assertNotNull(exception); + Assert.assertEquals(IllegalArgumentException.class, exception.getClass()); + Assert.assertEquals("Unexpected qualified name: [svc.schema]", exception.getMessage()); + + try { + qpsControllerManager.getOrCreate("..."); + } catch (Exception e) { + exception = e; + } + Assert.assertNotNull(exception); + Assert.assertEquals(IllegalArgumentException.class, exception.getClass()); + Assert.assertEquals("Unexpected qualified name: [...]", exception.getMessage()); + } + + private void testGetOrCreateCommon(QpsControllerManager testQpsControllerManager) { + // pojo.server + setConfigWithDefaultPrefix("pojo.server", 200); + QpsController qpsController = testQpsControllerManager.getOrCreate("pojo.server.test"); + Assert.assertEquals("pojo.server", qpsController.getKey()); + Assert.assertTrue(200 == qpsController.getQpsLimit()); + qpsController = testQpsControllerManager.getOrCreate("pojo.server2.test"); + Assert.assertEquals("pojo", qpsController.getKey()); + Assert.assertTrue(100 == qpsController.getQpsLimit()); + qpsController = testQpsControllerManager.getOrCreate("pojo.serve.test"); + Assert.assertEquals("pojo", qpsController.getKey()); + Assert.assertTrue(100 == qpsController.getQpsLimit()); + + // pojo.server.test + setConfigWithDefaultPrefix("pojo.server.test", 300); + qpsController = testQpsControllerManager.getOrCreate("pojo.server.test"); + Assert.assertEquals("pojo.server.test", qpsController.getKey()); + Assert.assertTrue(300 == qpsController.getQpsLimit()); + qpsController = testQpsControllerManager.getOrCreate("pojo.server.test2"); + Assert.assertEquals("pojo.server", qpsController.getKey()); + Assert.assertTrue(200 == qpsController.getQpsLimit()); + qpsController = testQpsControllerManager.getOrCreate("pojo.server.tes"); + Assert.assertEquals("pojo.server", qpsController.getKey()); + Assert.assertTrue(200 == qpsController.getQpsLimit()); + } + + /** + * Init testQpsControllerManager to test search function. + */ + private void initTestQpsControllerManager(QpsControllerManager testQpsControllerManager) { + // pojo.server.test + QpsController qpsController = testQpsControllerManager.getOrCreate("pojo.server.test"); + Assert.assertEquals("pojo", qpsController.getKey()); + Assert.assertNull(qpsController.getQpsLimit()); + + // pojo.server.test2 + testQpsControllerManager.getOrCreate("pojo.server.test2"); + + // pojo.server.tes + testQpsControllerManager.getOrCreate("pojo.server.tes"); + + // pojo.server2.test + testQpsControllerManager.getOrCreate("pojo.server2.test"); + + // pojo.serve.test + testQpsControllerManager.getOrCreate("pojo.serve.test"); + + // pojo2.server.test + qpsController = testQpsControllerManager.getOrCreate("pojo2.server.test"); + Assert.assertEquals("pojo2", qpsController.getKey()); + Assert.assertNull(qpsController.getQpsLimit()); + + // poj.server.test + qpsController = testQpsControllerManager.getOrCreate("poj.server.test"); + Assert.assertEquals("poj", qpsController.getKey()); + Assert.assertNull(qpsController.getQpsLimit()); + } + + @Test + public void testMock() { + Invocation invocation = getMockInvocation("service", "schema", "oper"); + OperationMeta operationMeta = invocation.getOperationMeta(); + SchemaMeta schemaMeta = operationMeta.getSchemaMeta(); + + Assert.assertEquals("service", operationMeta.getMicroserviceName()); + Assert.assertEquals("service.schema.oper", operationMeta.getMicroserviceQualifiedName()); + Assert.assertEquals("schema.oper", operationMeta.getSchemaQualifiedName()); + Assert.assertEquals("schema", schemaMeta.getSchemaId()); + } + + public static Invocation getMockInvocation(String microserviceName, String schemaId, String operationId) { + return getMockInvocation( + getMockOperationMeta(microserviceName, schemaId, operationId) + ); + } + + private static Invocation getMockInvocation(OperationMeta mockOperationMeta) { + Invocation invocation = Mockito.mock(Invocation.class); + Mockito.when(invocation.getOperationMeta()).thenReturn(mockOperationMeta); + return invocation; + } + + public static OperationMeta getMockOperationMeta(String microserviceName, String schemaId, String operationId) { + OperationMeta operationMeta = Mockito.mock(OperationMeta.class); + SchemaMeta schemaMeta = Mockito.mock(SchemaMeta.class); + + Mockito.when(operationMeta.getSchemaMeta()).thenReturn(schemaMeta); + Mockito.when(operationMeta.getSchemaQualifiedName()) + .thenReturn(schemaId + QpsControllerManager.SEPARATOR + operationId); + Mockito.when(operationMeta.getMicroserviceQualifiedName()).thenReturn( + microserviceName + QpsControllerManager.SEPARATOR + schemaId + QpsControllerManager.SEPARATOR + + operationId); + Mockito.when(operationMeta.getMicroserviceName()).thenReturn(microserviceName); + Mockito.when(schemaMeta.getSchemaId()).thenReturn(schemaId); + + return operationMeta; + } + + public static void setConfig(String key, int value) { + Utils.updateProperty(key, value); + } + + public static void setConfigWithDefaultPrefix(String key, int value) { + String configKey = Config.CONSUMER_LIMIT_KEY_PREFIX + key; + Utils.updateProperty(configKey, value); + } + + public static void clearState(QpsControllerManager qpsControllerManager) { + Map objMap = Deencapsulation.getField(qpsControllerManager, "qualifiedNameControllerMap"); + objMap.clear(); + Map configQpsControllerMap = Deencapsulation + .getField(qpsControllerManager, "configQpsControllerMap"); + configQpsControllerMap.clear(); + } +} diff --git a/handlers/handler-flowcontrol-qps/src/test/java/org/apache/servicecomb/qps/TestConsumerQpsControllermanager.java b/handlers/handler-flowcontrol-qps/src/test/java/org/apache/servicecomb/qps/TestConsumerQpsControllermanager.java deleted file mode 100644 index 426f7f8db0..0000000000 --- a/handlers/handler-flowcontrol-qps/src/test/java/org/apache/servicecomb/qps/TestConsumerQpsControllermanager.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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.servicecomb.qps; - -import org.apache.servicecomb.core.definition.OperationMeta; -import org.apache.servicecomb.core.definition.SchemaMeta; -import org.junit.Assert; -import org.junit.Test; - -import mockit.Expectations; -import mockit.Mocked; - -/** - * - * - */ -public class TestConsumerQpsControllermanager { - private static String microserviceName = "pojo"; - - private static String schemaQualified = microserviceName + ".server"; - - private static String operationQualified = schemaQualified + ".test"; - - @Test - public void testQpsLimit(@Mocked SchemaMeta schemaMeta, @Mocked OperationMeta operationMeta) { - new Expectations() { - { - operationMeta.getMicroserviceQualifiedName(); - result = operationQualified; - - schemaMeta.getMicroserviceQualifiedName(); - result = schemaQualified; - - operationMeta.getMicroserviceName(); - result = microserviceName; - } - }; - - ConsumerQpsControllerManager mgr = new ConsumerQpsControllerManager(); - QpsController qpsController = mgr.getOrCreate(operationMeta); - Assert.assertEquals((Integer) Integer.MAX_VALUE, qpsController.getQpsLimit()); - Assert.assertEquals(microserviceName, qpsController.getKey()); - - doTestQpsLimit(mgr, operationMeta, microserviceName, 100, microserviceName, 100); - doTestQpsLimit(mgr, operationMeta, schemaQualified, 200, schemaQualified, 200); - doTestQpsLimit(mgr, operationMeta, operationQualified, 300, operationQualified, 300); - doTestQpsLimit(mgr, operationMeta, operationQualified, null, schemaQualified, 200); - doTestQpsLimit(mgr, operationMeta, schemaQualified, null, microserviceName, 100); - doTestQpsLimit(mgr, operationMeta, microserviceName, null, microserviceName, Integer.MAX_VALUE); - } - - private void doTestQpsLimit(ConsumerQpsControllerManager mgr, OperationMeta operationMeta, String key, - Integer newValue, - String expectKey, Integer expectValue) { - Utils.updateProperty(Config.CONSUMER_LIMIT_KEY_PREFIX + key, newValue); - QpsController qpsController = mgr.getOrCreate(operationMeta); - Assert.assertEquals(expectValue, qpsController.getQpsLimit()); - Assert.assertEquals(expectKey, qpsController.getKey()); - } -} diff --git a/handlers/handler-flowcontrol-qps/src/test/java/org/apache/servicecomb/qps/TestConsumerQpsFlowControlHandler.java b/handlers/handler-flowcontrol-qps/src/test/java/org/apache/servicecomb/qps/TestConsumerQpsFlowControlHandler.java index 368459e196..6359a7eec1 100644 --- a/handlers/handler-flowcontrol-qps/src/test/java/org/apache/servicecomb/qps/TestConsumerQpsFlowControlHandler.java +++ b/handlers/handler-flowcontrol-qps/src/test/java/org/apache/servicecomb/qps/TestConsumerQpsFlowControlHandler.java @@ -17,20 +17,22 @@ package org.apache.servicecomb.qps; +import java.util.concurrent.ConcurrentHashMap; + import org.apache.servicecomb.core.Invocation; import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; import org.apache.servicecomb.swagger.invocation.AsyncResponse; +import org.junit.After; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; +import mockit.Deencapsulation; import mockit.Mock; import mockit.MockUp; -/** - * - * - */ public class TestConsumerQpsFlowControlHandler { ConsumerQpsFlowControlHandler handler = new ConsumerQpsFlowControlHandler(); @@ -41,8 +43,21 @@ public class TestConsumerQpsFlowControlHandler { OperationMeta operationMeta = Mockito.mock(OperationMeta.class); + @Before + public void setUP() { + ArchaiusUtils.resetConfig(); + QpsControllerManagerTest.clearState(ConsumerQpsFlowControlHandler.qpsControllerMgr); + } + + + @After + public void afterTest() { + ArchaiusUtils.resetConfig(); + QpsControllerManagerTest.clearState(ConsumerQpsFlowControlHandler.qpsControllerMgr); + } + @Test - public void testQpsController() throws Exception { + public void testQpsController() { QpsController qpsController = new QpsController("abc", 100); Assert.assertEquals(false, qpsController.isLimitNewRequest()); @@ -68,9 +83,11 @@ public void testHandle() { boolean validAssert; try { validAssert = true; + String key = "svc.schema.opr"; + QpsController qpsController = new QpsController("key", 12); Mockito.when(invocation.getOperationMeta()).thenReturn(operationMeta); - Mockito.when(operationMeta.getMicroserviceQualifiedName()).thenReturn("MicroserviceQualifiedName"); - + Mockito.when(operationMeta.getMicroserviceQualifiedName()).thenReturn(key); + setQpsController(key, qpsController); new MockUp() { @Mock public boolean isLimitNewRequest() { @@ -78,15 +95,15 @@ public boolean isLimitNewRequest() { } }; - new MockUp() { - + new MockUp() { @Mock - protected QpsController create(OperationMeta operationMeta) { - return new QpsController("key", 12); + protected QpsController create(String qualifiedNameKey) { + return qpsController; } }; handler.handle(invocation, asyncResp); } catch (Exception e) { + e.printStackTrace(); validAssert = false; } Assert.assertTrue(validAssert); @@ -97,8 +114,11 @@ public void testHandleIsLimitNewRequestAsFalse() { boolean validAssert; try { validAssert = true; + String key = "MicroserviceQualifiedName"; + QpsController qpsController = new QpsController("key", 12); Mockito.when(invocation.getOperationMeta()).thenReturn(operationMeta); - Mockito.when(operationMeta.getMicroserviceQualifiedName()).thenReturn("MicroserviceQualifiedName"); + Mockito.when(operationMeta.getMicroserviceQualifiedName()).thenReturn(key); + setQpsController(key, qpsController); new MockUp() { @Mock @@ -107,17 +127,25 @@ public boolean isLimitNewRequest() { } }; - new MockUp() { + new MockUp() { @Mock - protected QpsController create(OperationMeta operationMeta) { - return new QpsController("key", 12); + protected QpsController create(String qualifiedNameKey) { + return qpsController; } }; handler.handle(invocation, asyncResp); } catch (Exception e) { + e.printStackTrace(); validAssert = false; } Assert.assertTrue(validAssert); } + + private void setQpsController(String key, QpsController qpsController) { + QpsControllerManager qpsControllerManager = Deencapsulation.getField(handler, "qpsControllerMgr"); + ConcurrentHashMap objMap = Deencapsulation + .getField(qpsControllerManager, "qualifiedNameControllerMap"); + objMap.put(key, qpsController); + } } diff --git a/handlers/handler-flowcontrol-qps/src/test/java/org/apache/servicecomb/qps/TestProviderQpsControllermanager.java b/handlers/handler-flowcontrol-qps/src/test/java/org/apache/servicecomb/qps/TestProviderQpsControllermanager.java deleted file mode 100644 index c16f7092de..0000000000 --- a/handlers/handler-flowcontrol-qps/src/test/java/org/apache/servicecomb/qps/TestProviderQpsControllermanager.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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.servicecomb.qps; - -import org.junit.Assert; -import org.junit.Test; - -public class TestProviderQpsControllermanager { - private static String microserviceName = "pojo"; - - @Test - public void testQpsLimit() { - ProviderQpsControllerManager mgr = new ProviderQpsControllerManager(); - QpsController qpsController = mgr.getOrCreate(microserviceName); - Assert.assertEquals(null, qpsController.getQpsLimit()); - Assert.assertEquals(microserviceName, qpsController.getKey()); - - doTestQpsLimit(mgr, microserviceName, 100, microserviceName, 100); - doTestQpsLimit(mgr, microserviceName, null, microserviceName, null); - } - - private void doTestQpsLimit(ProviderQpsControllerManager mgr, String key, Integer newValue, - String expectKey, Integer expectValue) { - Utils.updateProperty(Config.PROVIDER_LIMIT_KEY_PREFIX + key, newValue); - QpsController qpsController = mgr.getOrCreate(key); - Assert.assertEquals(expectValue, qpsController.getQpsLimit()); - Assert.assertEquals(expectKey, qpsController.getKey()); - } -} diff --git a/handlers/handler-flowcontrol-qps/src/test/java/org/apache/servicecomb/qps/TestProviderQpsFlowControlHandler.java b/handlers/handler-flowcontrol-qps/src/test/java/org/apache/servicecomb/qps/TestProviderQpsFlowControlHandler.java index 40303db8e9..1bdf8a2152 100644 --- a/handlers/handler-flowcontrol-qps/src/test/java/org/apache/servicecomb/qps/TestProviderQpsFlowControlHandler.java +++ b/handlers/handler-flowcontrol-qps/src/test/java/org/apache/servicecomb/qps/TestProviderQpsFlowControlHandler.java @@ -17,10 +17,14 @@ package org.apache.servicecomb.qps; +import static org.junit.Assert.fail; + import org.apache.servicecomb.core.Const; import org.apache.servicecomb.core.Invocation; import org.apache.servicecomb.core.definition.OperationMeta; +import org.apache.servicecomb.foundation.test.scaffolding.config.ArchaiusUtils; import org.apache.servicecomb.swagger.invocation.AsyncResponse; +import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -42,9 +46,18 @@ public class TestProviderQpsFlowControlHandler { @Before public void setUP() { + ArchaiusUtils.resetConfig(); + QpsControllerManagerTest.clearState(ProviderQpsFlowControlHandler.qpsControllerMgr); Utils.updateProperty(Config.PROVIDER_LIMIT_KEY_PREFIX + "test", 1); } + + @After + public void afterTest() { + ArchaiusUtils.resetConfig(); + QpsControllerManagerTest.clearState(ProviderQpsFlowControlHandler.qpsControllerMgr); + } + @Test public void testGlobalQpsControl(final @Injectable Invocation invocation, final @Injectable AsyncResponse asyncResp) throws Exception { @@ -52,6 +65,8 @@ public void testGlobalQpsControl(final @Injectable Invocation invocation, { invocation.getContext(Const.SRC_MICROSERVICE); result = "test"; + invocation.getOperationMeta(); + result = QpsControllerManagerTest.getMockOperationMeta("pojo", "server", "opr"); asyncResp.producerFail((Throwable) any); result = new RuntimeException("test error"); } @@ -67,7 +82,7 @@ public void testGlobalQpsControl(final @Injectable Invocation invocation, gHandler.handle(invocation, asyncResp); count++; gHandler.handle(invocation, asyncResp); - Assert.assertTrue(false); + fail("An exception is expected!"); } catch (Exception e) { Assert.assertEquals(2, count); Assert.assertEquals("test error", e.getMessage()); @@ -75,7 +90,7 @@ public void testGlobalQpsControl(final @Injectable Invocation invocation, } @Test - public void testQpsController() throws Exception { + public void testQpsController() { QpsController qpsController = new QpsController("abc", 100); Assert.assertEquals(false, qpsController.isLimitNewRequest()); @@ -93,6 +108,7 @@ public void testHandleWithException() { handler.handle(invocation, asyncResp); handler.handle(invocation, asyncResp); } catch (Exception e) { + e.printStackTrace(); validAssert = false; } Assert.assertTrue(validAssert); @@ -104,6 +120,8 @@ public void testHandle() { try { validAssert = true; Mockito.when(invocation.getContext(Const.SRC_MICROSERVICE)).thenReturn("test"); + OperationMeta mockOperationMeta = QpsControllerManagerTest.getMockOperationMeta("pojo", "server", "opr"); + Mockito.when(invocation.getOperationMeta()).thenReturn(mockOperationMeta); new MockUp() { @Mock @@ -112,15 +130,16 @@ public boolean isLimitNewRequest() { } }; - new MockUp() { + new MockUp() { @Mock - protected QpsController create(String serviceName) { - return new QpsController(serviceName, 12); + protected QpsController create(String qualifiedNameKey) { + return new QpsController(qualifiedNameKey, 12); } }; handler.handle(invocation, asyncResp); } catch (Exception e) { + e.printStackTrace(); validAssert = false; } Assert.assertTrue(validAssert); @@ -132,6 +151,9 @@ public void testHandleIsLimitNewRequestAsFalse() { try { validAssert = true; Mockito.when(invocation.getContext(Const.SRC_MICROSERVICE)).thenReturn("test"); + OperationMeta mockOperationMeta = QpsControllerManagerTest + .getMockOperationMeta("pojo", "server", "opr"); + Mockito.when(invocation.getOperationMeta()).thenReturn(mockOperationMeta); new MockUp() { @Mock @@ -140,15 +162,16 @@ public boolean isLimitNewRequest() { } }; - new MockUp() { + new MockUp() { @Mock - protected QpsController create(String serviceName) { - return new QpsController(serviceName, 12); + protected QpsController create(String qualifiedNameKey) { + return new QpsController(qualifiedNameKey, 12); } }; handler.handle(invocation, asyncResp); } catch (Exception e) { + e.printStackTrace(); validAssert = false; } Assert.assertTrue(validAssert);