You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by li...@apache.org on 2018/03/22 09:16:36 UTC
[incubator-servicecomb-java-chassis] 01/05: Fault-Injection handler
implementation
This is an automated email from the ASF dual-hosted git repository.
liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-servicecomb-java-chassis.git
commit 28eedb4b2493430d39e82903ba87010edd0e06ef
Author: maheshrajus <ma...@huawei.com>
AuthorDate: Tue Mar 20 22:27:24 2018 +0530
Fault-Injection handler implementation
---
coverage-reports/pom.xml | 4 +
handlers/handler-fault-injection/pom.xml | 44 ++
.../servicecomb/faultinjection/AbortFault.java | 64 ++
.../servicecomb/faultinjection/AbstractFault.java | 25 +
.../servicecomb/faultinjection/BeanHolder.java | 47 ++
.../servicecomb/faultinjection/DelayFault.java | 81 +++
.../apache/servicecomb/faultinjection/Fault.java | 27 +
.../faultinjection/FaultInjectionConfig.java | 59 ++
.../faultinjection/FaultInjectionConst.java | 36 ++
.../faultinjection/FaultInjectionHandler.java | 72 +++
.../faultinjection/FaultInjectionUtil.java | 168 +++++
.../servicecomb/faultinjection/FaultParam.java | 37 ++
.../servicecomb/faultinjection/FaultResponse.java | 63 ++
.../main/resources/META-INF/spring/cse.bean.xml} | 37 +-
.../src/main/resources/config/cse.handler.xml | 21 +
.../faultinjection/TestFaultInjectConfig.java | 102 +++
.../faultinjection/TestFaultInjectHandler.java | 683 +++++++++++++++++++++
.../faultinjection/TestFaultInjectUtil.java | 73 +++
handlers/pom.xml | 1 +
java-chassis-dependencies/pom.xml | 5 +
java-chassis-distribution/pom.xml | 4 +
21 files changed, 1629 insertions(+), 24 deletions(-)
diff --git a/coverage-reports/pom.xml b/coverage-reports/pom.xml
index 27a6c0e..337ae26 100644
--- a/coverage-reports/pom.xml
+++ b/coverage-reports/pom.xml
@@ -72,6 +72,10 @@
</dependency>
<dependency>
<groupId>org.apache.servicecomb</groupId>
+ <artifactId>handler-fault-injection</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.servicecomb</groupId>
<artifactId>common-rest</artifactId>
</dependency>
<dependency>
diff --git a/handlers/handler-fault-injection/pom.xml b/handlers/handler-fault-injection/pom.xml
new file mode 100755
index 0000000..3fda7b4
--- /dev/null
+++ b/handlers/handler-fault-injection/pom.xml
@@ -0,0 +1,44 @@
+<!--
+ ~ 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.
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.servicecomb</groupId>
+ <artifactId>handlers</artifactId>
+ <version>1.0.0-m2-SNAPSHOT</version>
+ </parent>
+ <artifactId>handler-fault-injection</artifactId>
+ <name>Java Chassis::Handlers::Fault Injection</name>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.servicecomb</groupId>
+ <artifactId>java-chassis-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/AbortFault.java b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/AbortFault.java
new file mode 100644
index 0000000..3bf4d84
--- /dev/null
+++ b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/AbortFault.java
@@ -0,0 +1,64 @@
+/*
+ * 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.faultinjection;
+
+import org.apache.servicecomb.core.Invocation;
+import org.apache.servicecomb.swagger.invocation.exception.CommonExceptionData;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+@Component
+public class AbortFault extends AbstractFault {
+ private static final Logger LOGGER = LoggerFactory.getLogger(FaultInjectionConfig.class);
+
+ @Override
+ public FaultResponse injectFault(Invocation invocation, FaultParam faultParam) {
+ // get the config values related to delay.
+ int abortPercent = FaultInjectionUtil.getFaultInjectionConfig(invocation,
+ "abort.percent");
+
+ if (abortPercent == FaultInjectionConst.FAULT_INJECTION_CFG_NULL) {
+ LOGGER.info("Fault injection: Abort percentage is not configured");
+ return new FaultResponse();
+ }
+
+ // check fault abort condition.
+ boolean isAbort = FaultInjectionUtil.checkFaultInjectionDelayAndAbort(faultParam.getReqCount(), abortPercent);
+ if (isAbort) {
+ // get the config values related to delay percentage.
+ int errorCode = FaultInjectionUtil.getFaultInjectionConfig(invocation,
+ "abort.httpStatus");
+
+ if (errorCode == FaultInjectionConst.FAULT_INJECTION_CFG_NULL) {
+ LOGGER.info("Fault injection: Abort error code is not configured");
+ return new FaultResponse();
+ }
+ // if request need to be abort then return failure with given error code
+ CommonExceptionData errorData = new CommonExceptionData("aborted by fault inject");
+ return new FaultResponse(-1, errorCode, errorData);
+ }
+
+ return new FaultResponse();
+ }
+
+ @Override
+ public int getPriority() {
+ return FaultInjectionConst.FAULTINJECTION_PRIORITY_MIN;
+ }
+}
diff --git a/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/AbstractFault.java b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/AbstractFault.java
new file mode 100644
index 0000000..db88a5e
--- /dev/null
+++ b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/AbstractFault.java
@@ -0,0 +1,25 @@
+/*
+ * 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.faultinjection;
+
+import org.springframework.stereotype.Component;
+
+@Component
+public abstract class AbstractFault implements Fault {
+
+}
diff --git a/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/BeanHolder.java b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/BeanHolder.java
new file mode 100644
index 0000000..756ad4b
--- /dev/null
+++ b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/BeanHolder.java
@@ -0,0 +1,47 @@
+/*
+ * 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.faultinjection;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.springframework.stereotype.Component;
+
+@Component
+public class BeanHolder {
+
+ @Inject
+ private List<Fault> faultInjectionFeatureList = Collections.emptyList();
+
+ public void init() {
+ //sort the fault injection feature list based on priority.
+ Collections.sort(faultInjectionFeatureList, new Comparator<Fault>() {
+
+ @Override
+ public int compare(Fault o1, Fault o2) {
+ return Integer.compare(o1.getPriority(), o2.getPriority());
+ }
+ });
+
+ FaultInjectionHandler.getFaultFeature().addAll(faultInjectionFeatureList);
+
+ }
+}
diff --git a/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/DelayFault.java b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/DelayFault.java
new file mode 100644
index 0000000..5ab0ed9
--- /dev/null
+++ b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/DelayFault.java
@@ -0,0 +1,81 @@
+/*
+ * 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.faultinjection;
+
+import java.util.concurrent.CountDownLatch;
+
+import org.apache.servicecomb.core.Invocation;
+import org.apache.servicecomb.foundation.vertx.VertxUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import io.vertx.core.Handler;
+import io.vertx.core.Vertx;
+
+@Component
+public class DelayFault extends AbstractFault {
+ private static final Logger LOGGER = LoggerFactory.getLogger(FaultInjectionHandler.class);
+
+ @Override
+ public int getPriority() {
+ return FaultInjectionConst.FAULTINJECTION_PRIORITY_MAX;
+ }
+
+ @Override
+ public FaultResponse injectFault(Invocation invocation, FaultParam faultAttributes) {
+ int delayPercent = FaultInjectionUtil.getFaultInjectionConfig(invocation,
+ "delay.percent");
+
+ if (delayPercent == FaultInjectionConst.FAULT_INJECTION_CFG_NULL) {
+ LOGGER.info("Fault injection: delay percentage is not configured");
+ return new FaultResponse();
+ }
+
+ // check fault delay condition.
+ boolean isDelay = FaultInjectionUtil.checkFaultInjectionDelayAndAbort(faultAttributes.getReqCount(), delayPercent);
+ if (isDelay) {
+ LOGGER.info("Fault injection: delay is added for the request by fault inject handler");
+ long delay = FaultInjectionUtil.getFaultInjectionConfig(invocation,
+ "delay.fixedDelay");
+
+ if (delay == FaultInjectionConst.FAULT_INJECTION_CFG_NULL) {
+ LOGGER.info("Fault injection: delay is not configured");
+ return new FaultResponse();
+ }
+
+ CountDownLatch latch = new CountDownLatch(1);
+ Vertx vertx = VertxUtils.getOrCreateVertxByName("faultinjection", null);
+ vertx.setTimer(delay, new Handler<Long>() {
+ @Override
+ public void handle(Long timeID) {
+ latch.countDown();
+ }
+ });
+
+ try {
+ latch.await();
+ } catch (InterruptedException e) {
+ LOGGER.info("Interrupted exception is received");
+ }
+ }
+
+ return new FaultResponse();
+ }
+
+}
diff --git a/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/Fault.java b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/Fault.java
new file mode 100644
index 0000000..9d17e07
--- /dev/null
+++ b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/Fault.java
@@ -0,0 +1,27 @@
+/*
+ * 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.faultinjection;
+
+import org.apache.servicecomb.core.Invocation;
+
+public interface Fault {
+
+ int getPriority();
+
+ FaultResponse injectFault(Invocation invocation, FaultParam faultAttributes);
+}
diff --git a/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultInjectionConfig.java b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultInjectionConfig.java
new file mode 100755
index 0000000..f6000e5
--- /dev/null
+++ b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultInjectionConfig.java
@@ -0,0 +1,59 @@
+/*
+ * 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.faultinjection;
+
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.netflix.config.DynamicIntProperty;
+import com.netflix.config.DynamicPropertyFactory;
+
+/**
+ * Handles the fault injection configuration read from micro service file/config
+ * center.
+ */
+public final class FaultInjectionConfig {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(FaultInjectionConfig.class);
+
+ // key is configuration parameter.
+ private static Map<String, String> cfgCallback = new ConcurrentHashMapEx<>();
+
+ public static int getConfigVal(String config, int defaultValue) {
+ DynamicIntProperty dynamicIntProperty = DynamicPropertyFactory.getInstance().getIntProperty(config,
+ defaultValue);
+
+ if (cfgCallback.get(config) == null) {
+ cfgCallback.put(config, config);
+ dynamicIntProperty.addCallback(() -> {
+ int newValue = dynamicIntProperty.get();
+ String cfgName = dynamicIntProperty.getName();
+
+ //store the value in config center map and check for next requests.
+ FaultInjectionUtil.setConfigCenterValue(cfgName, new AtomicInteger(newValue));
+ LOGGER.info("{} changed to {}", cfgName, newValue);
+ });
+ }
+
+ return dynamicIntProperty.get();
+ }
+}
diff --git a/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultInjectionConst.java b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultInjectionConst.java
new file mode 100644
index 0000000..fdc2a8b
--- /dev/null
+++ b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultInjectionConst.java
@@ -0,0 +1,36 @@
+/*
+ * 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.faultinjection;
+
+/**
+ * Handles the all constant values for fault injection.
+ */
+public class FaultInjectionConst {
+
+ public static final int FAULT_INJECTION_CFG_NULL = -1;
+
+ public static final String CONSUMER_FAULTINJECTION = "cse.governance.Consumer.";
+
+ public static final String CONSUMER_FAULTINJECTION_GLOBAL = "cse.governance.Consumer._global.";
+
+ public static final String CONSUMER_FAULTINJECTION_POLICY_PROTOCOLS = "policy.fault.protocols.";
+
+ public static final int FAULTINJECTION_PRIORITY_MIN = 10;
+
+ public static final int FAULTINJECTION_PRIORITY_MAX = 1;
+}
diff --git a/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultInjectionHandler.java b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultInjectionHandler.java
new file mode 100755
index 0000000..090b5a9
--- /dev/null
+++ b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultInjectionHandler.java
@@ -0,0 +1,72 @@
+/*
+ * 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.faultinjection;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.apache.servicecomb.core.Handler;
+import org.apache.servicecomb.core.Invocation;
+import org.apache.servicecomb.swagger.invocation.AsyncResponse;
+import org.apache.servicecomb.swagger.invocation.context.HttpStatus;
+import org.apache.servicecomb.swagger.invocation.exception.InvocationException;
+
+/**
+ * Fault injection handler which injects the delay/abort for requests based on
+ * the percentage configured in service file.
+ *
+ */
+
+public class FaultInjectionHandler implements Handler {
+
+ private static List<Fault> faultInjectionFeatureList = new ArrayList<>();
+
+ //added only for unit testing
+ public void setFaultFeature(List<Fault> faultFeature) {
+ faultInjectionFeatureList = faultFeature;
+ }
+
+ public static List<Fault> getFaultFeature() {
+ return faultInjectionFeatureList;
+ }
+
+ @Override
+ public void handle(Invocation invocation, AsyncResponse asyncResp) throws Exception {
+
+ // prepare the key and lookup for request count.
+ String key = invocation.getTransport().getName() + invocation.getMicroserviceQualifiedName();
+ AtomicLong reqCount = FaultInjectionUtil.getOperMetTotalReq(key);
+ long reqCountCurrent = reqCount.get();
+
+ // increment the request count here after checking the delay/abort condition.
+ reqCount.incrementAndGet();
+
+ for (Fault fault : faultInjectionFeatureList) {
+ FaultResponse faultResponse = fault.injectFault(invocation, new FaultParam(reqCountCurrent));
+
+ if (faultResponse.getStatusCode() != 0) {
+ asyncResp.consumerFail(new InvocationException(new HttpStatus(faultResponse.getErrorCode(),
+ "invocation exception induced by fault injection"), faultResponse.getErrorData()));
+ return;
+ }
+ }
+
+ invocation.next(asyncResp);
+ }
+}
diff --git a/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultInjectionUtil.java b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultInjectionUtil.java
new file mode 100755
index 0000000..2ff4abf
--- /dev/null
+++ b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultInjectionUtil.java
@@ -0,0 +1,168 @@
+/*
+ * 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.faultinjection;
+
+import static org.apache.servicecomb.faultinjection.FaultInjectionConst.CONSUMER_FAULTINJECTION;
+import static org.apache.servicecomb.faultinjection.FaultInjectionConst.CONSUMER_FAULTINJECTION_GLOBAL;
+import static org.apache.servicecomb.faultinjection.FaultInjectionConst.CONSUMER_FAULTINJECTION_POLICY_PROTOCOLS;
+import static org.apache.servicecomb.faultinjection.FaultInjectionConst.FAULT_INJECTION_CFG_NULL;
+
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.apache.servicecomb.core.Invocation;
+import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx;
+
+/**
+ * Handles the count for all request based key[transport + microservice qualified name].
+ */
+public class FaultInjectionUtil {
+
+ // key is transport+operQualifiedName
+ private static Map<String, AtomicLong> requestCount = new ConcurrentHashMapEx<>();
+
+ // key is config paramter
+ private static Map<String, AtomicInteger> configCenterValue = new ConcurrentHashMapEx<>();
+
+ /**
+ * Returns total requests per provider for operational level.
+ *
+ * @param key
+ * transport+operational name
+ * @return long total requests
+ */
+ public static AtomicLong getOperMetTotalReq(String key) {
+ return requestCount.computeIfAbsent(key, p -> new AtomicLong(1));
+ }
+
+ /**
+ * Returns the map of config parameter key and values.
+ * @return value of config parameter map
+ */
+ public static Map<String, AtomicInteger> getConfigCenterMap() {
+ return configCenterValue;
+ }
+
+ /**
+ * Sets the value for given config parameter.
+ * @param key
+ * @param value
+ */
+ public static void setConfigCenterValue(String key, AtomicInteger value) {
+ configCenterValue.put(key, value);
+ }
+
+ /**
+ * Handles the reading fault injection configuration.
+ *
+ * @param invocation
+ * invocation of request
+ * @param key
+ * configuration key
+ * @return configuration value
+ */
+ public static int getFaultInjectionConfig(Invocation invocation, String key) {
+ int value = 0;
+ String config;
+
+ // get the config base on priority. operationName-->schema-->service-->global
+ String operationName = invocation.getOperationName();
+ String schema = invocation.getSchemaId();
+ String serviceName = invocation.getMicroserviceName();
+
+ config = CONSUMER_FAULTINJECTION + serviceName + ".schemas." + schema + ".operations." + operationName + "."
+ + CONSUMER_FAULTINJECTION_POLICY_PROTOCOLS + invocation.getTransport().getName() + "." + key;
+
+ value = getConfigValue(config);
+ if ((value != FAULT_INJECTION_CFG_NULL)) {
+ return value;
+ }
+
+ config = CONSUMER_FAULTINJECTION + serviceName + ".schemas." + schema + "."
+ + CONSUMER_FAULTINJECTION_POLICY_PROTOCOLS + invocation.getTransport().getName() + "." + key;
+
+ value = getConfigValue(config);
+ if ((value != FAULT_INJECTION_CFG_NULL)) {
+ return value;
+ }
+
+ config = CONSUMER_FAULTINJECTION + serviceName + "." + CONSUMER_FAULTINJECTION_POLICY_PROTOCOLS
+ + invocation.getTransport().getName() + "." + key;
+ value = getConfigValue(config);
+ if ((value != FAULT_INJECTION_CFG_NULL)) {
+ return value;
+ }
+
+ config = CONSUMER_FAULTINJECTION_GLOBAL + CONSUMER_FAULTINJECTION_POLICY_PROTOCOLS
+ + invocation.getTransport().getName() + "." + key;
+
+ value = getConfigValue(config);
+ return value;
+ }
+
+ /**
+ * Get the configuration value
+ * @param config config parameter
+ * @return int value
+ */
+ private static int getConfigValue(String config) {
+ int value = 0;
+ //first need to check in config center map which has high priority.
+ Map<String, AtomicInteger> cfgMap = FaultInjectionUtil.getConfigCenterMap();
+
+ if (cfgMap.containsKey(config)) {
+ return cfgMap.get(config).get();
+ }
+
+ value = FaultInjectionConfig.getConfigVal(config, FAULT_INJECTION_CFG_NULL);
+ return value;
+
+ }
+
+ /**
+ * It will check the delay/abort condition based on request count and percentage
+ * received.
+ *
+ * @param reqCount
+ * @param percentage
+ * @param key
+ * @return true/false
+ */
+ public static boolean checkFaultInjectionDelayAndAbort(long reqCount, int percentage) {
+ /*
+ * Example: delay/abort percentage configured is 10% and Get the count(suppose
+ * if it is 10th request) from map and calculate resultNew(10th request) and
+ * requestOld(9th request). Like this for every request it will calculate
+ * current request count and previous count. if both not matched need to add
+ * delay/abort otherwise no need to add.
+ */
+
+ // calculate the value with current request count.
+ long resultNew = (reqCount * percentage) / 100;
+
+ // calculate the value with previous count value.
+ long resultOld = ((reqCount - 1) * percentage) / 100;
+
+ // if both are not matching then delay/abort should be added.
+ if (resultNew != resultOld) {
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultParam.java b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultParam.java
new file mode 100644
index 0000000..0dcd19b
--- /dev/null
+++ b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultParam.java
@@ -0,0 +1,37 @@
+/*
+ * 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.faultinjection;
+
+/**
+ * Fault injection parameters which decides the fault injection condition.
+ */
+public class FaultParam {
+ private long reqCount;
+
+ public long getReqCount() {
+ return reqCount;
+ }
+
+ public void setReqCount(long reqCount) {
+ this.reqCount = reqCount;
+ }
+
+ FaultParam(long reqCount) {
+ this.reqCount = reqCount;
+ }
+}
diff --git a/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultResponse.java b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultResponse.java
new file mode 100644
index 0000000..ee59d71
--- /dev/null
+++ b/handlers/handler-fault-injection/src/main/java/org/apache/servicecomb/faultinjection/FaultResponse.java
@@ -0,0 +1,63 @@
+/*
+ * 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.faultinjection;
+
+/**
+ * Fault response which contains status of fault injection.
+ */
+public class FaultResponse {
+ private int statusCode;
+
+ private int errorCode;
+
+ private Object errorData;
+
+ FaultResponse(int statusCode, int errorCode, Object errorData) {
+ this.statusCode = statusCode;
+ this.errorCode = errorCode;
+ this.errorData = errorData;
+ }
+
+ FaultResponse() {
+ }
+
+ public int getStatusCode() {
+ return statusCode;
+ }
+
+ public void setStatusCode(int statusCode) {
+ this.statusCode = statusCode;
+ }
+
+ public int getErrorCode() {
+ return errorCode;
+ }
+
+ public void setErrorCode(int errorCode) {
+ this.errorCode = errorCode;
+ }
+
+ public Object getErrorData() {
+ return errorData;
+ }
+
+ public void setErrorData(Object errorData) {
+ this.errorData = errorData;
+ }
+
+}
diff --git a/handlers/pom.xml b/handlers/handler-fault-injection/src/main/resources/META-INF/spring/cse.bean.xml
old mode 100644
new mode 100755
similarity index 51%
copy from handlers/pom.xml
copy to handlers/handler-fault-injection/src/main/resources/META-INF/spring/cse.bean.xml
index 2afaa77..b8f5c57
--- a/handlers/pom.xml
+++ b/handlers/handler-fault-injection/src/main/resources/META-INF/spring/cse.bean.xml
@@ -16,27 +16,16 @@
~ limitations under the License.
-->
-<project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <parent>
- <groupId>org.apache.servicecomb</groupId>
- <artifactId>java-chassis-parent</artifactId>
- <version>1.0.0-m2-SNAPSHOT</version>
- <relativePath>../parent</relativePath>
- </parent>
- <modelVersion>4.0.0</modelVersion>
-
- <artifactId>handlers</artifactId>
- <name>Java Chassis::Handlers</name>
- <packaging>pom</packaging>
-
- <modules>
- <module>handler-tracing-zipkin</module>
- <module>handler-bizkeeper</module>
- <module>handler-flowcontrol-qps</module>
- <module>handler-loadbalance</module>
- <module>handler-publickey-auth</module>
- </modules>
-
-</project>
+ <beans xmlns = "http://www.springframework.org/schema/beans"
+ xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:context = "http://www.springframework.org/schema/context"
+ xsi:schemaLocation = "http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+ http://www.springframework.org/schema/context
+ http://www.springframework.org/schema/context/spring-context-3.0.xsd">
+
+ <context:annotation-config />
+ <!-- <context:spring-configured /> -->
+ <context:component-scan base-package="org.apache.servicecomb.faultinjection" />
+ <bean class="org.apache.servicecomb.faultinjection.BeanHolder" init-method="init"/>
+</beans>
diff --git a/handlers/handler-fault-injection/src/main/resources/config/cse.handler.xml b/handlers/handler-fault-injection/src/main/resources/config/cse.handler.xml
new file mode 100755
index 0000000..477963b
--- /dev/null
+++ b/handlers/handler-fault-injection/src/main/resources/config/cse.handler.xml
@@ -0,0 +1,21 @@
+<!--
+ ~ 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.
+ -->
+
+<config>
+ <handler id="fault-injection"
+ class="org.apache.servicecomb.faultinjection.FaultInjectionHandler" />
+</config>
diff --git a/handlers/handler-fault-injection/src/test/java/org/apache/servicecomb/faultinjection/TestFaultInjectConfig.java b/handlers/handler-fault-injection/src/test/java/org/apache/servicecomb/faultinjection/TestFaultInjectConfig.java
new file mode 100644
index 0000000..f4d3137
--- /dev/null
+++ b/handlers/handler-fault-injection/src/test/java/org/apache/servicecomb/faultinjection/TestFaultInjectConfig.java
@@ -0,0 +1,102 @@
+/*
+ * 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.faultinjection;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests the fault injection configuration.
+ */
+public class TestFaultInjectConfig {
+ FaultInjectionConfig faultCfg;
+
+ FaultInjectionConst faultConst;
+
+ FaultInjectionUtil faultUtil;
+
+ FaultParam faultParam;
+
+ FaultResponse faultResp;
+
+ AbortFault abortFault;
+
+ DelayFault delayFault;
+
+ @Before
+ public void setUp() throws Exception {
+ faultCfg = new FaultInjectionConfig();
+ faultConst = new FaultInjectionConst();
+ faultUtil = new FaultInjectionUtil();
+ faultParam = new FaultParam(10);
+ faultResp = new FaultResponse();
+ abortFault = new AbortFault();
+ delayFault = new DelayFault();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ faultCfg = null;
+ faultConst = null;
+ faultUtil = null;
+ faultParam = null;
+ }
+
+ @Test
+ public void testFaultInjectConfig() throws Exception {
+ int val = FaultInjectionConfig.getConfigVal("cse.servicecomb.handler.consumer.faultinject.config", 0);
+ Assert.assertEquals(0, val);
+ }
+
+ @Test
+ public void testConstants() {
+ assertEquals("cse.governance.Consumer.", FaultInjectionConst.CONSUMER_FAULTINJECTION);
+ assertEquals("policy.fault.protocols.", FaultInjectionConst.CONSUMER_FAULTINJECTION_POLICY_PROTOCOLS);
+ assertEquals(-1, FaultInjectionConst.FAULT_INJECTION_CFG_NULL);
+ assertEquals("cse.governance.Consumer._global.", FaultInjectionConst.CONSUMER_FAULTINJECTION_GLOBAL);
+ assertEquals(10, FaultInjectionConst.FAULTINJECTION_PRIORITY_MIN);
+ assertEquals(1, FaultInjectionConst.FAULTINJECTION_PRIORITY_MAX);
+ }
+
+ @Test
+ public void testFaultParam() {
+ faultParam.setReqCount(100);
+ assertEquals(100, faultParam.getReqCount());
+ }
+
+ @Test
+ public void testFaultResponse() {
+ Object obj = new Object();
+ faultResp.setErrorCode(100);
+ faultResp.setErrorData(obj);
+ faultResp.setStatusCode(123);
+ assertEquals(123, faultResp.getStatusCode());
+ assertEquals(100, faultResp.getErrorCode());
+ assertEquals(obj, faultResp.getErrorData());
+ }
+
+ @Test
+ public void testFaultPriority() {
+ assertEquals(10, abortFault.getPriority());
+ assertEquals(1, delayFault.getPriority());
+ }
+}
diff --git a/handlers/handler-fault-injection/src/test/java/org/apache/servicecomb/faultinjection/TestFaultInjectHandler.java b/handlers/handler-fault-injection/src/test/java/org/apache/servicecomb/faultinjection/TestFaultInjectHandler.java
new file mode 100644
index 0000000..7288f78
--- /dev/null
+++ b/handlers/handler-fault-injection/src/test/java/org/apache/servicecomb/faultinjection/TestFaultInjectHandler.java
@@ -0,0 +1,683 @@
+/*
+ * 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.faultinjection;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.apache.servicecomb.core.Invocation;
+import org.apache.servicecomb.core.Transport;
+import org.apache.servicecomb.core.definition.OperationMeta;
+import org.apache.servicecomb.swagger.invocation.AsyncResponse;
+import org.apache.servicecomb.swagger.invocation.Response;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests the fault injection handler functionality.
+ */
+public class TestFaultInjectHandler {
+ FaultInjectionHandler handler;
+
+ Invocation invocation;
+
+ AsyncResponse asyncResp;
+
+ OperationMeta operationMeta;
+
+ private Transport transport;
+
+ Response response;
+
+
+ @InjectMocks
+ FaultInjectionHandler faultHandler;
+
+ @InjectMocks
+ AbortFault abortFault;
+
+ @InjectMocks
+ DelayFault delayFault;
+
+ AsyncResponse ar = new AsyncResponse() {
+ @Override
+ public void handle(Response resp) {
+ response = resp;
+ }
+ };
+
+
+ @Before
+ public void setUp() throws Exception {
+ handler = new FaultInjectionHandler();
+
+ invocation = Mockito.mock(Invocation.class);
+
+ asyncResp = Mockito.mock(AsyncResponse.class);
+
+ operationMeta = Mockito.mock(OperationMeta.class);
+
+ transport = Mockito.mock(Transport.class);
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ handler = null;
+
+ invocation = null;
+
+ asyncResp = null;
+
+ operationMeta = null;
+
+ transport = null;
+ }
+
+ /**
+ * Tests the fault injection handler functionality with default values for
+ * highway transport.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testFaultInjectHandlerHighwayWithDefaultCfg() throws Exception {
+
+ Mockito.when(invocation.getMicroserviceQualifiedName()).thenReturn("MicroserviceQualifiedName1");
+ Mockito.when(invocation.getTransport()).thenReturn(transport);
+ Mockito.when(transport.getName()).thenReturn("highway");
+ Mockito.when(invocation.getOperationName()).thenReturn("sayHello");
+ Mockito.when(invocation.getSchemaId()).thenReturn("sayHelloSchema");
+ Mockito.when(invocation.getMicroserviceName()).thenReturn("hello");
+
+
+ List<Fault> faultInjectionFeatureList = Arrays.asList(abortFault, delayFault);
+ handler.setFaultFeature(faultInjectionFeatureList);
+
+ handler.handle(invocation, asyncResp);
+
+ AtomicLong count = FaultInjectionUtil.getOperMetTotalReq("highwayMicroserviceQualifiedName1");
+ assertEquals(2, count.get());
+ }
+
+ /**
+ * Tests the fault injection handler functionality with default values for rest
+ * transport.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testFaultInjectHandlerRestWithDefaultCfg() throws Exception {
+
+ Mockito.when(invocation.getMicroserviceQualifiedName()).thenReturn("MicroserviceQualifiedName2");
+ Mockito.when(invocation.getTransport()).thenReturn(transport);
+ Mockito.when(transport.getName()).thenReturn("rest");
+ Mockito.when(invocation.getOperationName()).thenReturn("sayHello");
+ Mockito.when(invocation.getSchemaId()).thenReturn("sayHelloSchema");
+ Mockito.when(invocation.getMicroserviceName()).thenReturn("hello");
+
+ List<Fault> faultInjectionFeatureList = Arrays.asList(abortFault, delayFault);
+ handler.setFaultFeature(faultInjectionFeatureList);
+
+ handler.handle(invocation, asyncResp);
+
+ AtomicLong count = FaultInjectionUtil.getOperMetTotalReq("restMicroserviceQualifiedName2");
+ assertEquals(2, count.get());
+ }
+
+ /**
+ * Tests the fault injection handler functionality with global configuration
+ * with delay/abort condition.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testFaultInjectHandlerConfigChangeGlobal() throws Exception {
+
+ System.setProperty("cse.governance.Consumer._global.policy.fault.protocols.rest.delay.fixedDelay", "5");
+ System.setProperty("cse.governance.Consumer._global.policy.fault.protocols.rest.delay.percent", "10");
+ System.setProperty("cse.governance.Consumer._global.policy.fault.protocols.rest.abort.percent", "10");
+ System.setProperty("cse.governance.Consumer._global.policy.fault.protocols.rest.abort.httpStatus", "421");
+
+ Mockito.when(invocation.getMicroserviceQualifiedName()).thenReturn("MicroserviceQualifiedName3");
+ Mockito.when(invocation.getTransport()).thenReturn(transport);
+ Mockito.when(transport.getName()).thenReturn("rest");
+ Mockito.when(invocation.getOperationName()).thenReturn("sayHello");
+ Mockito.when(invocation.getSchemaId()).thenReturn("sayHelloSchema");
+ Mockito.when(invocation.getMicroserviceName()).thenReturn("hello");
+
+ List<Fault> faultInjectionFeatureList = Arrays.asList(abortFault, delayFault);
+ handler.setFaultFeature(faultInjectionFeatureList);
+
+ boolean validAssert;
+ try {
+ validAssert = true;
+ handler.handle(invocation, asyncResp);
+ } catch (Exception e) {
+ validAssert = false;
+ }
+
+ System.getProperties().remove("cse.governance.Consumer._global.policy.fault.protocols.rest.delay.fixedDelay");
+ System.getProperties().remove("cse.governance.Consumer._global.policy.fault.protocols.rest.delay.percent");
+ System.getProperties().remove("cse.governance.Consumer._global.policy.fault.protocols.rest.abort.percent");
+ System.getProperties().remove("cse.governance.Consumer._global.policy.fault.protocols.rest.abort.httpStatus");
+
+ Assert.assertTrue(validAssert);
+ AtomicLong count = FaultInjectionUtil.getOperMetTotalReq("restMicroserviceQualifiedName3");
+ assertEquals(2, count.get());
+ }
+
+ /**
+ * Tests the fault injection handler functionality with service level configuration
+ * with delay/abort condition.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testFaultInjectHandlerServiceCfgSuccess() throws Exception {
+
+ System.setProperty("cse.governance.Consumer.carts.policy.fault.protocols.rest.delay.fixedDelay", "1");
+ System.setProperty("cse.governance.Consumer.carts.policy.fault.protocols.rest.delay.percent", "10");
+ System.setProperty("cse.governance.Consumer.carts.policy.fault.protocols.rest.abort.percent", "10");
+ System.setProperty("cse.governance.Consumer.carts.policy.fault.protocols.rest.abort.httpStatus", "421");
+
+ Mockito.when(invocation.getMicroserviceQualifiedName()).thenReturn("MicroserviceQualifiedName4");
+ Mockito.when(invocation.getTransport()).thenReturn(transport);
+ Mockito.when(transport.getName()).thenReturn("rest");
+ Mockito.when(invocation.getOperationName()).thenReturn("sayHello");
+ Mockito.when(invocation.getSchemaId()).thenReturn("sayHelloSchema");
+ Mockito.when(invocation.getMicroserviceName()).thenReturn("carts");
+
+ List<Fault> faultInjectionFeatureList = Arrays.asList(abortFault, delayFault);
+ handler.setFaultFeature(faultInjectionFeatureList);
+
+ boolean validAssert;
+ try {
+ validAssert = true;
+ handler.handle(invocation, asyncResp);
+ } catch (Exception e) {
+ validAssert = false;
+ }
+
+ System.getProperties().remove("cse.governance.Consumer.carts.policy.fault.protocols.rest.delay.fixedDelay");
+ System.getProperties().remove("cse.governance.Consumer.carts.policy.fault.protocols.rest.delay.percent");
+ System.getProperties().remove("cse.governance.Consumer.carts.policy.fault.protocols.rest.abort.percent");
+ System.getProperties().remove("cse.governance.Consumer.carts.policy.fault.protocols.rest.abort.httpStatus");
+
+ Assert.assertTrue(validAssert);
+ AtomicLong count = FaultInjectionUtil.getOperMetTotalReq("restMicroserviceQualifiedName4");
+ assertEquals(2, count.get());
+ }
+
+ /**
+ * Tests the fault injection handler functionality with schema level configuration
+ * with delay/abort condition.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testFaultInjectHandlerSchemaCfgSuccess() throws Exception {
+
+ System.setProperty("cse.governance.Consumer.carts.schemas.testSchema.policy.fault.protocols.rest.delay.fixedDelay",
+ "1");
+ System.setProperty("cse.governance.Consumer.carts.schemas.testSchema.policy.fault.protocols.rest.delay.percent",
+ "10");
+ System.setProperty("cse.governance.Consumer.carts.schemas.testSchema.policy.fault.protocols.rest.abort.percent",
+ "10");
+ System.setProperty("cse.governance.Consumer.carts.schemas.testSchema.policy.fault.protocols.rest.abort.httpStatus",
+ "421");
+
+ Mockito.when(invocation.getMicroserviceQualifiedName()).thenReturn("MicroserviceQualifiedName5");
+ Mockito.when(invocation.getTransport()).thenReturn(transport);
+ Mockito.when(transport.getName()).thenReturn("rest");
+ Mockito.when(invocation.getOperationName()).thenReturn("sayHello");
+ Mockito.when(invocation.getSchemaId()).thenReturn("testSchema");
+ Mockito.when(invocation.getMicroserviceName()).thenReturn("carts");
+
+ List<Fault> faultInjectionFeatureList = Arrays.asList(abortFault, delayFault);
+ handler.setFaultFeature(faultInjectionFeatureList);
+
+ boolean validAssert;
+ try {
+ validAssert = true;
+ handler.handle(invocation, asyncResp);
+ } catch (Exception e) {
+ validAssert = false;
+ }
+
+ System.getProperties()
+ .remove("cse.governance.Consumer.carts.schemas.testSchema.policy.fault.protocols.rest.delay.fixedDelay");
+ System.getProperties()
+ .remove("cse.governance.Consumer.carts.schemas.testSchema.policy.fault.protocols.rest.delay.percent");
+ System.getProperties()
+ .remove("cse.governance.Consumer.carts.schemas.testSchema.policy.fault.protocols.rest.abort.percent");
+ System.getProperties()
+ .remove("cse.governance.Consumer.carts.schemas.testSchema.policy.fault.protocols.rest.abort.httpStatus");
+
+ Assert.assertTrue(validAssert);
+ AtomicLong count = FaultInjectionUtil.getOperMetTotalReq("restMicroserviceQualifiedName5");
+ assertEquals(2, count.get());
+ }
+
+ /**
+ * Tests the fault injection handler functionality with operation level configuration
+ * with delay/abort condition.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testFaultInjectHandlerOperationCfgSuccess() throws Exception {
+
+ System.setProperty(
+ "cse.governance.Consumer.carts.schemas.testSchema.operations.sayHi.policy.fault.protocols.rest.delay.fixedDelay",
+ "1");
+ System.setProperty(
+ "cse.governance.Consumer.carts.schemas.testSchema.operations.sayHi.policy.fault.protocols.rest.delay.percent",
+ "10");
+ System.setProperty(
+ "cse.governance.Consumer.carts.schemas.testSchema.operations.sayHi.policy.fault.protocols.rest.abort.percent",
+ "10");
+ System.setProperty(
+ "cse.governance.Consumer.carts.schemas.testSchema.operations.sayHi.policy.fault.protocols.rest.abort.httpStatus",
+ "421");
+
+ Mockito.when(invocation.getMicroserviceQualifiedName()).thenReturn("MicroserviceQualifiedName6");
+ Mockito.when(invocation.getTransport()).thenReturn(transport);
+ Mockito.when(transport.getName()).thenReturn("rest");
+ Mockito.when(invocation.getOperationName()).thenReturn("sayHi");
+ Mockito.when(invocation.getSchemaId()).thenReturn("testSchema");
+ Mockito.when(invocation.getMicroserviceName()).thenReturn("carts");
+
+ List<Fault> faultInjectionFeatureList = Arrays.asList(abortFault, delayFault);
+ handler.setFaultFeature(faultInjectionFeatureList);
+
+ boolean validAssert;
+ try {
+ validAssert = true;
+ handler.handle(invocation, asyncResp);
+ } catch (Exception e) {
+ validAssert = false;
+ }
+
+ System.getProperties()
+ .remove(
+ "cse.governance.Consumer.carts.schemas.testSchema.operations.sayHi.policy.fault.protocols.rest.delay.fixedDelay");
+ System.getProperties()
+ .remove(
+ "cse.governance.Consumer.carts.schemas.testSchema.operations.sayHi.policy.fault.protocols.rest.delay.percent");
+ System.getProperties()
+ .remove(
+ "cse.governance.Consumer.carts.schemas.testSchema.operations.sayHi.policy.fault.protocols.rest.abort.percent");
+ System.getProperties()
+ .remove(
+ "cse.governance.Consumer.carts.schemas.testSchema.operations.sayHi.policy.fault.protocols.rest.abort.httpStatus");
+ Assert.assertTrue(validAssert);
+ AtomicLong count = FaultInjectionUtil.getOperMetTotalReq("restMicroserviceQualifiedName6");
+ assertEquals(2, count.get());
+ }
+
+ /**
+ * Tests the fault injection handler functionality with configuration change event for global level config.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testFaultInjectHandlerConfigChangeEvent1() throws Exception {
+
+ System.setProperty(
+ "cse.governance.Consumer._global.policy.fault.protocols.rest.delay.fixedDelay",
+ "1");
+ System.setProperty(
+ "cse.governance.Consumer._global.policy.fault.protocols.rest.delay.percent",
+ "100");
+ System.setProperty(
+ "cse.governance.Consumer._global.policy.fault.protocols.rest.abort.percent",
+ "100");
+ System.setProperty(
+ "cse.governance.Consumer._global.policy.fault.protocols.rest.abort.httpStatus",
+ "420");
+
+ Mockito.when(invocation.getMicroserviceQualifiedName()).thenReturn("MicroserviceQualifiedName7");
+ Mockito.when(invocation.getTransport()).thenReturn(transport);
+ Mockito.when(transport.getName()).thenReturn("rest");
+ Mockito.when(invocation.getOperationName()).thenReturn("sayBye1");
+ Mockito.when(invocation.getSchemaId()).thenReturn("testSchema1");
+ Mockito.when(invocation.getMicroserviceName()).thenReturn("carts1");
+ boolean validAssert;
+ long timeOld = System.currentTimeMillis();
+
+ List<Fault> faultInjectionFeatureList = Arrays.asList(delayFault, abortFault);
+ handler.setFaultFeature(faultInjectionFeatureList);
+
+ try {
+ validAssert = true;
+ handler.handle(invocation, ar);
+ } catch (Exception e) {
+ validAssert = false;
+ }
+ Assert.assertTrue(validAssert);
+ TestFaultInjectUtil
+ .updateProperty("cse.governance.Consumer._global.policy.fault.protocols.rest.delay.fixedDelay", 500);
+ TestFaultInjectUtil
+ .updateProperty("cse.governance.Consumer._global.policy.fault.protocols.rest.abort.httpStatus", 421);
+
+ handler.handle(invocation, ar -> {
+ //check whether error code return, defaut is 421.
+ assertEquals(421, response.getStatusCode());
+ assertEquals(true, response.isFailed());
+ long timeNow = System.currentTimeMillis();
+ //if really time delay is added it should be greater than 5s.
+ Assert.assertTrue((timeNow - timeOld) >= 500);
+ });
+
+
+ System.getProperties()
+ .remove(
+ "cse.governance.Consumer._global.policy.fault.protocols.rest.delay.fixedDelay");
+ System.getProperties()
+ .remove(
+ "cse.governance.Consumer._global.policy.fault.protocols.rest.delay.percent");
+ System.getProperties()
+ .remove(
+ "cse.governance.Consumer._global.policy.fault.protocols.rest.abort.percent");
+ System.getProperties()
+ .remove(
+ "cse.governance.Consumer._global.policy.fault.protocols.rest.abort.httpStatus");
+
+ AtomicLong count = FaultInjectionUtil.getOperMetTotalReq("restMicroserviceQualifiedName7");
+ assertEquals(3, count.get());
+
+ }
+
+ /**
+ * Tests the fault injection handler functionality with configuration change event for operation level config.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testFaultInjectHandlerConfigChangeEvent2() throws Exception {
+
+ System.setProperty(
+ "cse.governance.Consumer.carts2.schemas.testSchema2.operations.sayBye2.policy.fault.protocols.rest.delay.fixedDelay",
+ "1");
+ System.setProperty(
+ "cse.governance.Consumer.carts2.schemas.testSchema2.operations.sayBye2.policy.fault.protocols.rest.delay.percent",
+ "100");
+ System.setProperty(
+ "cse.governance.Consumer.carts2.schemas.testSchema2.operations.sayBye2.policy.fault.protocols.rest.abort.percent",
+ "100");
+ System.setProperty(
+ "cse.governance.Consumer.carts2.schemas.testSchema2.operations.sayBye2.policy.fault.protocols.rest.abort.httpStatus",
+ "420");
+
+
+ Mockito.when(invocation.getMicroserviceQualifiedName()).thenReturn("MicroserviceQualifiedName8");
+ Mockito.when(invocation.getTransport()).thenReturn(transport);
+ Mockito.when(transport.getName()).thenReturn("rest");
+ Mockito.when(invocation.getOperationName()).thenReturn("sayBye2");
+ Mockito.when(invocation.getSchemaId()).thenReturn("testSchema2");
+ Mockito.when(invocation.getMicroserviceName()).thenReturn("carts2");
+ boolean validAssert;
+ long timeOld = System.currentTimeMillis();
+
+ List<Fault> faultInjectionFeatureList = Arrays.asList(delayFault, abortFault);
+ handler.setFaultFeature(faultInjectionFeatureList);
+
+ try {
+ validAssert = true;
+ handler.handle(invocation, ar);
+ } catch (Exception e) {
+ validAssert = false;
+ }
+ Assert.assertTrue(validAssert);
+ TestFaultInjectUtil
+ .updateProperty(
+ "cse.governance.Consumer.carts2.schemas.testSchema2.operations.sayBye2.policy.fault.protocols.rest.delay.fixedDelay",
+ 500);
+
+ handler.handle(invocation, ar -> {
+ //check whether error code return
+ assertEquals(420, response.getStatusCode());
+ assertEquals(true, response.isFailed());
+ long timeNow = System.currentTimeMillis();
+ //if really time delay is added it should be greater than 5s.
+ Assert.assertTrue((timeNow - timeOld) >= 500);
+ });
+
+ System.getProperties()
+ .remove(
+ "cse.governance.Consumer.carts2.schemas.testSchema2.operations.sayBye2.policy.fault.protocols.rest.delay.fixedDelay");
+ System.getProperties()
+ .remove(
+ "cse.governance.Consumer.carts2.schemas.testSchema2.operations.sayBye2.policy.fault.protocols.rest.delay.percent");
+ System.getProperties()
+ .remove(
+ "cse.governance.Consumer.carts2.schemas.testSchema2.operations.sayBye2.policy.fault.protocols.rest.abort.percent");
+ System.getProperties()
+ .remove(
+ "cse.governance.Consumer.carts2.schemas.testSchema2.operations.sayBye2.policy.fault.protocols.rest.abort.httpStatus");
+
+
+ AtomicLong count = FaultInjectionUtil.getOperMetTotalReq("restMicroserviceQualifiedName8");
+ assertEquals(3, count.get());
+
+ }
+
+ /**
+ * Tests the fault injection handler functionality with configuration change event for schema level config.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testFaultInjectHandlerConfigChangeEvent3() throws Exception {
+
+ System.setProperty(
+ "cse.governance.Consumer.carts3.schemas.testSchema3.policy.fault.protocols.rest.delay.fixedDelay",
+ "1");
+ System.setProperty(
+ "cse.governance.Consumer.carts3.schemas.testSchema3.policy.fault.protocols.rest.delay.percent",
+ "100");
+ System.setProperty(
+ "cse.governance.Consumer.carts3.schemas.testSchema3.policy.fault.protocols.rest.abort.percent",
+ "100");
+ System.setProperty(
+ "cse.governance.Consumer.carts3.schemas.testSchema3.policy.fault.protocols.rest.abort.httpStatus",
+ "421");
+
+ Mockito.when(invocation.getMicroserviceQualifiedName()).thenReturn("MicroserviceQualifiedName9");
+ Mockito.when(invocation.getTransport()).thenReturn(transport);
+ Mockito.when(transport.getName()).thenReturn("rest");
+ Mockito.when(invocation.getOperationName()).thenReturn("sayBye3");
+ Mockito.when(invocation.getSchemaId()).thenReturn("testSchema3");
+ Mockito.when(invocation.getMicroserviceName()).thenReturn("carts3");
+ boolean validAssert;
+ long timeOld = System.currentTimeMillis();
+
+ List<Fault> faultInjectionFeatureList = Arrays.asList(delayFault, abortFault);
+ handler.setFaultFeature(faultInjectionFeatureList);
+
+ try {
+ validAssert = true;
+ handler.handle(invocation, ar);
+ } catch (Exception e) {
+ validAssert = false;
+ }
+ Assert.assertTrue(validAssert);
+ TestFaultInjectUtil
+ .updateProperty(
+ "cse.governance.Consumer.carts3.schemas.testSchema3.policy.fault.protocols.rest.delay.fixedDelay",
+ 500);
+
+ handler.handle(invocation, ar -> {
+ //check whether error code return, defaut is 421.
+ assertEquals(421, response.getStatusCode());
+ assertEquals(true, response.isFailed());
+ long timeNow = System.currentTimeMillis();
+ //if really time delay is added it should be greater than 5s.
+ Assert.assertTrue((timeNow - timeOld) >= 500);
+ });
+
+ System.getProperties()
+ .remove("cse.governance.Consumer.carts3.schemas.testSchema3.policy.fault.protocols.rest.delay.fixedDelay");
+ System.getProperties()
+ .remove("cse.governance.Consumer.carts3.schemas.testSchema3.policy.fault.protocols.rest.delay.percent");
+ System.getProperties()
+ .remove("cse.governance.Consumer.carts3.schemas.testSchema3.policy.fault.protocols.rest.abort.percent");
+ System.getProperties()
+ .remove("cse.governance.Consumer.carts3.schemas.testSchema3.policy.fault.protocols.rest.abort.httpStatus");
+
+
+ AtomicLong count = FaultInjectionUtil.getOperMetTotalReq("restMicroserviceQualifiedName9");
+ assertEquals(3, count.get());
+ }
+
+ /**
+ * Tests the fault injection handler functionality with configuration change event for service level config.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testFaultInjectHandlerConfigChangeEvent4() throws Exception {
+ System.setProperty("cse.governance.Consumer.carts4.policy.fault.protocols.rest.delay.fixedDelay", "1");
+
+ System.setProperty(
+ "cse.governance.Consumer.carts4.policy.fault.protocols.rest.delay.percent",
+ "100");
+ System.setProperty(
+ "cse.governance.Consumer.carts4.policy.fault.protocols.rest.abort.percent",
+ "100");
+ System.setProperty(
+ "cse.governance.Consumer.carts4.policy.fault.protocols.rest.abort.httpStatus",
+ "421");
+
+ Mockito.when(invocation.getMicroserviceQualifiedName()).thenReturn("MicroserviceQualifiedName10");
+ Mockito.when(invocation.getTransport()).thenReturn(transport);
+ Mockito.when(transport.getName()).thenReturn("rest");
+ Mockito.when(invocation.getOperationName()).thenReturn("sayBye4");
+ Mockito.when(invocation.getSchemaId()).thenReturn("testSchema4");
+ Mockito.when(invocation.getMicroserviceName()).thenReturn("carts4");
+ boolean validAssert;
+ long timeOld = System.currentTimeMillis();
+
+ List<Fault> faultInjectionFeatureList = Arrays.asList(delayFault, abortFault);
+ handler.setFaultFeature(faultInjectionFeatureList);
+
+ try {
+ validAssert = true;
+ handler.handle(invocation, ar);
+ } catch (Exception e) {
+ validAssert = false;
+ }
+ Assert.assertTrue(validAssert);
+ TestFaultInjectUtil
+ .updateProperty("cse.governance.Consumer.carts4.policy.fault.protocols.rest.delay.fixedDelay", 500);
+
+ handler.handle(invocation, ar -> {
+ //check whether error code return,
+ assertEquals(421, response.getStatusCode());
+ assertEquals(true, response.isFailed());
+ long timeNow = System.currentTimeMillis();
+ //if really time delay is added it should be greater than 5s.
+ Assert.assertTrue((timeNow - timeOld) >= 500);
+ });
+
+
+ System.getProperties()
+ .remove("cse.governance.Consumer.carts4.policy.fault.protocols.rest.delay.fixedDelay");
+ System.getProperties()
+ .remove("cse.governance.Consumer.carts4.policy.fault.protocols.rest.delay.percent");
+ System.getProperties()
+ .remove("cse.governance.Consumer.carts4.policy.fault.protocols.rest.abort.percent");
+ System.getProperties()
+ .remove("cse.governance.Consumer.carts4.policy.fault.protocols.rest.abort.httpStatus");
+
+
+ AtomicLong count = FaultInjectionUtil.getOperMetTotalReq("restMicroserviceQualifiedName10");
+ assertEquals(3, count.get());
+
+ }
+
+ /**
+ * Tests the fault injection handler functionality with configuration change event for service level config.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testFaultInjectHandlerConfigChangeEvent5() throws Exception {
+ System.setProperty(
+ "cse.governance.Consumer.carts5.policy.fault.protocols.rest.delay.percent",
+ "100");
+ System.setProperty(
+ "cse.governance.Consumer.carts5.policy.fault.protocols.rest.abort.percent",
+ "100");
+
+ Mockito.when(invocation.getMicroserviceQualifiedName()).thenReturn("MicroserviceQualifiedName11");
+ Mockito.when(invocation.getTransport()).thenReturn(transport);
+ Mockito.when(transport.getName()).thenReturn("rest");
+ Mockito.when(invocation.getOperationName()).thenReturn("sayBye4");
+ Mockito.when(invocation.getSchemaId()).thenReturn("testSchema4");
+ Mockito.when(invocation.getMicroserviceName()).thenReturn("carts5");
+ boolean validAssert;
+ long timeOld = System.currentTimeMillis();
+
+ List<Fault> faultInjectionFeatureList = Arrays.asList(delayFault, abortFault);
+ handler.setFaultFeature(faultInjectionFeatureList);
+
+ try {
+ validAssert = true;
+ handler.handle(invocation, ar);
+ } catch (Exception e) {
+ validAssert = false;
+ }
+ Assert.assertTrue(validAssert);
+ TestFaultInjectUtil
+ .updateProperty("cse.governance.Consumer.carts5.policy.fault.protocols.rest.abort.percent", 500);
+
+ handler.handle(invocation, ar -> {
+ //check whether error code return,
+ assertEquals(421, response.getStatusCode());
+ assertEquals(true, response.isFailed());
+ long timeNow = System.currentTimeMillis();
+ //if really time delay is added it should be greater than 5s.
+ Assert.assertTrue((timeNow - timeOld) >= 500);
+ });
+
+
+ System.getProperties()
+ .remove("cse.governance.Consumer.carts5.policy.fault.protocols.rest.delay.fixedDelay");
+ System.getProperties()
+ .remove("cse.governance.Consumer.carts5.policy.fault.protocols.rest.delay.percent");
+ System.getProperties()
+ .remove("cse.governance.Consumer.carts5.policy.fault.protocols.rest.abort.percent");
+ System.getProperties()
+ .remove("cse.governance.Consumer.carts5.policy.fault.protocols.rest.abort.httpStatus");
+
+
+ AtomicLong count = FaultInjectionUtil.getOperMetTotalReq("restMicroserviceQualifiedName11");
+ assertEquals(3, count.get());
+
+ }
+}
diff --git a/handlers/handler-fault-injection/src/test/java/org/apache/servicecomb/faultinjection/TestFaultInjectUtil.java b/handlers/handler-fault-injection/src/test/java/org/apache/servicecomb/faultinjection/TestFaultInjectUtil.java
new file mode 100644
index 0000000..46b428e
--- /dev/null
+++ b/handlers/handler-fault-injection/src/test/java/org/apache/servicecomb/faultinjection/TestFaultInjectUtil.java
@@ -0,0 +1,73 @@
+/*
+ * 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.faultinjection;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.springframework.util.ReflectionUtils;
+
+import com.netflix.config.DynamicProperty;
+
+/**
+ * Tests the fault inject util functionality.
+ */
+public class TestFaultInjectUtil {
+ private static Method updatePropertyMethod =
+ ReflectionUtils.findMethod(DynamicProperty.class, "updateProperty", String.class, Object.class);
+
+ static {
+ updatePropertyMethod.setAccessible(true);
+ }
+
+ DelayFault delayFault = Mockito.mock(DelayFault.class);
+
+ AbortFault abortFault = Mockito.mock(AbortFault.class);
+
+ public static void updateProperty(String key, Object value) {
+ ReflectionUtils.invokeMethod(updatePropertyMethod, null, key, value);
+ }
+
+ @Test
+ public void testFaultInjectUtil() throws Exception {
+ BeanHolder beanHolder = new BeanHolder();
+ List<Fault> faultInjectionFeatureList = Arrays.asList(delayFault, abortFault);
+ Field field = beanHolder.getClass().getDeclaredField("faultInjectionFeatureList");
+ field.setAccessible(true);
+ field.set(beanHolder, faultInjectionFeatureList);
+ Mockito.when(delayFault.getPriority()).thenReturn(1);
+ Mockito.when(abortFault.getPriority()).thenReturn(10);
+
+ beanHolder.init();
+ AtomicLong count1 = FaultInjectionUtil.getOperMetTotalReq("test");
+ Assert.assertEquals(1, count1.get());
+ count1.incrementAndGet();
+ AtomicLong count2 = FaultInjectionUtil.getOperMetTotalReq("test");
+ Assert.assertEquals(2, count2.get());
+ FaultInjectionUtil.setConfigCenterValue("sayHi", new AtomicInteger(123));
+ int value = FaultInjectionUtil.getConfigCenterMap().get("sayHi").get();
+ Assert.assertEquals(123, value);
+ }
+}
diff --git a/handlers/pom.xml b/handlers/pom.xml
index 2afaa77..a16e93e 100644
--- a/handlers/pom.xml
+++ b/handlers/pom.xml
@@ -36,6 +36,7 @@
<module>handler-bizkeeper</module>
<module>handler-flowcontrol-qps</module>
<module>handler-loadbalance</module>
+ <module>handler-fault-injection</module>
<module>handler-publickey-auth</module>
</modules>
diff --git a/java-chassis-dependencies/pom.xml b/java-chassis-dependencies/pom.xml
index 5793296..e9ae9ec 100644
--- a/java-chassis-dependencies/pom.xml
+++ b/java-chassis-dependencies/pom.xml
@@ -836,6 +836,11 @@
</dependency>
<dependency>
<groupId>org.apache.servicecomb</groupId>
+ <artifactId>handler-fault-injection</artifactId>
+ <version>1.0.0-m2-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.servicecomb</groupId>
<artifactId>common-rest</artifactId>
<version>1.0.0-m2-SNAPSHOT</version>
</dependency>
diff --git a/java-chassis-distribution/pom.xml b/java-chassis-distribution/pom.xml
index 1b7f364..95b30e1 100644
--- a/java-chassis-distribution/pom.xml
+++ b/java-chassis-distribution/pom.xml
@@ -129,6 +129,10 @@
<artifactId>handler-tracing-zipkin</artifactId>
</dependency>
<dependency>
+ <groupId>org.apache.servicecomb</groupId>
+ <artifactId>handler-fault-injection</artifactId>
+ </dependency>
+ <dependency>
<groupId>org.apache.servicecomb</groupId>
<artifactId>provider-jaxrs</artifactId>
</dependency>
--
To stop receiving notification emails like this one, please contact
liubao@apache.org.