Skip to content

Commit 40e0e3f

Browse files
xinlian12annie-mac
andauthored
faultInjectionOnGateway (Azure#35378)
* faultInjectionOnGateway --------- Co-authored-by: annie-mac <[email protected]>
1 parent b2a3869 commit 40e0e3f

File tree

60 files changed

+2860
-475
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+2860
-475
lines changed

sdk/cosmos/azure-cosmos-test/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
### 1.0.0-beta.4 (Unreleased)
44

55
#### Features Added
6+
* Added fault injection support for Gateway connection mode - See [PR 35378](https://github.com/Azure/azure-sdk-for-java/pull/35378)
67

78
#### Breaking Changes
89

sdk/cosmos/azure-cosmos-test/src/main/java/com/azure/cosmos/test/faultinjection/FaultInjectionCondition.java

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
package com.azure.cosmos.test.faultinjection;
55

6+
import com.azure.cosmos.test.implementation.ImplementationBridgeHelpers;
7+
68
/***
79
* Fault injection condition.
810
* A fault injection rule will not be applicable if the condition mismatches.
@@ -19,7 +21,7 @@ public final class FaultInjectionCondition {
1921
String region,
2022
FaultInjectionEndpoints endpoints) {
2123
this.operationType = operationType;
22-
this.connectionType = connectionType;
24+
this.connectionType = this.isMetadataOperationType() ? FaultInjectionConnectionType.GATEWAY : connectionType;
2325
this.region = region;
2426
this.endpoints = endpoints;
2527
}
@@ -60,6 +62,18 @@ public String getRegion() {
6062
return this.region;
6163
}
6264

65+
boolean isMetadataOperationType() {
66+
if (this.operationType == null) {
67+
return false;
68+
}
69+
70+
return this.operationType == FaultInjectionOperationType.METADATA_REQUEST_PARTITION_KEY_RANGES
71+
|| this.operationType == FaultInjectionOperationType.METADATA_REQUEST_ADDRESS_REFRESH
72+
|| this.operationType == FaultInjectionOperationType.METADATA_REQUEST_CONTAINER
73+
|| this.operationType == FaultInjectionOperationType.METADATA_REQUEST_QUERY_PLAN
74+
|| this.operationType == FaultInjectionOperationType.METADATA_REQUEST_DATABASE_ACCOUNT;
75+
}
76+
6377
@Override
6478
public String toString() {
6579
return String.format(
@@ -69,4 +83,17 @@ public String toString() {
6983
this.connectionType,
7084
this.region);
7185
}
86+
87+
///////////////////////////////////////////////////////////////////////////////////////////
88+
// the following helper/accessor only helps to access this class outside of this package.//
89+
///////////////////////////////////////////////////////////////////////////////////////////
90+
static void initialize() {
91+
ImplementationBridgeHelpers.FaultInjectionConditionHelper.setFaultInjectionConditionAccessor(
92+
faultInjectionCondition -> faultInjectionCondition.isMetadataOperationType()
93+
);
94+
}
95+
96+
static {
97+
initialize();
98+
}
7299
}

sdk/cosmos/azure-cosmos-test/src/main/java/com/azure/cosmos/test/faultinjection/FaultInjectionConnectionType.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,9 @@ public enum FaultInjectionConnectionType {
1010
/***
1111
* Direct connection type.
1212
*/
13-
DIRECT
13+
DIRECT,
14+
/***
15+
* Gateway connection type.
16+
*/
17+
GATEWAY
1418
}

sdk/cosmos/azure-cosmos-test/src/main/java/com/azure/cosmos/test/faultinjection/FaultInjectionOperationType.java

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,25 @@ public enum FaultInjectionOperationType {
3434
/**
3535
* Patch item.
3636
*/
37-
PATCH_ITEM
38-
39-
// Add support for metadata request type
37+
PATCH_ITEM,
38+
/**
39+
* Read container request.
40+
*/
41+
METADATA_REQUEST_CONTAINER,
42+
/**
43+
* Read database account request.
44+
*/
45+
METADATA_REQUEST_DATABASE_ACCOUNT,
46+
/**
47+
* Query query plan request.
48+
*/
49+
METADATA_REQUEST_QUERY_PLAN,
50+
/**
51+
* Partition key ranges request.
52+
*/
53+
METADATA_REQUEST_PARTITION_KEY_RANGES,
54+
/**
55+
* Address refresh request.
56+
*/
57+
METADATA_REQUEST_ADDRESS_REFRESH;
4058
}

sdk/cosmos/azure-cosmos-test/src/main/java/com/azure/cosmos/test/faultinjection/FaultInjectionRuleBuilder.java

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package com.azure.cosmos.test.faultinjection;
55

66
import com.azure.cosmos.implementation.apachecommons.lang.StringUtils;
7+
import com.azure.cosmos.test.implementation.ImplementationBridgeHelpers;
78

89
import java.time.Duration;
910

@@ -117,10 +118,21 @@ public FaultInjectionRuleBuilder enabled(boolean enabled) {
117118
* Create a new fault injection rule.
118119
*
119120
* @return the {@link FaultInjectionRule}.
121+
* @throws IllegalArgumentException if condition is null.
122+
* @throws IllegalArgumentException if result is null.
120123
*/
121124
public FaultInjectionRule build() {
122-
checkNotNull(this.condition, "Argument 'condition' can not be null");
123-
checkNotNull(this.result, "Argument 'result' can not be null");
125+
if (this.condition == null) {
126+
throw new IllegalArgumentException("Argument 'condition' can not be null");
127+
}
128+
129+
if (this.result == null) {
130+
throw new IllegalArgumentException("Argument 'result' can not be null");
131+
}
132+
133+
if (this.condition.getConnectionType() == FaultInjectionConnectionType.GATEWAY) {
134+
this.validateRuleOnGatewayConnection();
135+
}
124136

125137
return new FaultInjectionRule(
126138
this.id,
@@ -131,4 +143,38 @@ public FaultInjectionRule build() {
131143
this.condition,
132144
this.result);
133145
}
146+
147+
private void validateRuleOnGatewayConnection() {
148+
if (this.result == null) {
149+
throw new IllegalArgumentException("Argument 'result' can not be null");
150+
}
151+
152+
if (this.result instanceof FaultInjectionConnectionErrorResult) {
153+
throw new IllegalArgumentException("FaultInjectionConnectionError result can not be configured for rule with gateway connection type.");
154+
}
155+
156+
FaultInjectionServerErrorResult serverErrorResult = (FaultInjectionServerErrorResult) this.result;
157+
158+
// Gateway service internally will retry for 410/0, so the eventual exceptions being returned to SDK is 503(SERVICE_UNAVAILABLE) instead
159+
if (serverErrorResult.getServerErrorType() == FaultInjectionServerErrorType.GONE) {
160+
throw new IllegalArgumentException("Gone exception can not be injected for rule with gateway connection type");
161+
}
162+
163+
if (serverErrorResult.getServerErrorType() == FaultInjectionServerErrorType.STALED_ADDRESSES_SERVER_GONE) {
164+
throw new IllegalArgumentException("STALED_ADDRESSES exception can not be injected for rule with gateway connection type");
165+
}
166+
167+
// for metadata request related rule, only CONNECTION_DELAY, RESPONSE_DELAY, TOO_MANY_REQUEST error can be injected
168+
if (ImplementationBridgeHelpers
169+
.FaultInjectionConditionHelper
170+
.getFaultInjectionConditionAccessor()
171+
.isMetadataOperationType(this.condition)) {
172+
if (serverErrorResult.getServerErrorType() != FaultInjectionServerErrorType.TOO_MANY_REQUEST
173+
&& serverErrorResult.getServerErrorType() != FaultInjectionServerErrorType.RESPONSE_DELAY
174+
&& serverErrorResult.getServerErrorType() != FaultInjectionServerErrorType.CONNECTION_DELAY) {
175+
176+
throw new IllegalArgumentException("Error type " + serverErrorResult.getServerErrorType() + " is not supported for rule with metadata request");
177+
}
178+
}
179+
}
134180
}

sdk/cosmos/azure-cosmos-test/src/main/java/com/azure/cosmos/test/faultinjection/FaultInjectionServerErrorResultBuilder.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,12 @@ public FaultInjectionServerErrorResult build() {
8383
throw new IllegalArgumentException("Argument 'delay' is required for server error type " + this.serverErrorType);
8484
}
8585

86+
if (this.serverErrorType == FaultInjectionServerErrorType.STALED_ADDRESSES_SERVER_GONE) {
87+
// for staled addresses errors, the error can only be cleared if forceRefresh address refresh request happened
88+
// so default the times to max value
89+
this.times = Integer.MAX_VALUE;
90+
}
91+
8692
return new FaultInjectionServerErrorResult(
8793
this.serverErrorType,
8894
this.times,

sdk/cosmos/azure-cosmos-test/src/main/java/com/azure/cosmos/test/faultinjection/FaultInjectionServerErrorType.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*/
99
public enum FaultInjectionServerErrorType {
1010

11-
/** 410 from server */
11+
/** 410 from server. Only applicable for direct connection type. */
1212
GONE,
1313

1414
/** 449 from server */
@@ -36,5 +36,13 @@ public enum FaultInjectionServerErrorType {
3636
RESPONSE_DELAY,
3737

3838
/** simulate high channel acquisition, when it is over connection timeout, can simulate connectionTimeoutException */
39-
CONNECTION_DELAY
39+
CONNECTION_DELAY,
40+
/**
41+
* Simulate service unavailable(503)
42+
*/
43+
SERVICE_UNAVAILABLE,
44+
/**
45+
* simulate 410-0 due to staled addresses. The exception will only be cleared if a forceRefresh address refresh happened.
46+
*/
47+
STALED_ADDRESSES_SERVER_GONE
4048
}

sdk/cosmos/azure-cosmos-test/src/main/java/com/azure/cosmos/test/implementation/ImplementationBridgeHelpers.java

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33

44
package com.azure.cosmos.test.implementation;
55

6-
import com.azure.cosmos.test.implementation.faultinjection.IFaultInjectionRuleInternal;
6+
import com.azure.cosmos.test.faultinjection.FaultInjectionCondition;
77
import com.azure.cosmos.test.faultinjection.FaultInjectionRule;
8+
import com.azure.cosmos.test.implementation.faultinjection.IFaultInjectionRuleInternal;
89
import org.slf4j.Logger;
910
import org.slf4j.LoggerFactory;
1011

@@ -52,4 +53,42 @@ public interface FaultInjectionRuleAccessor {
5253
void setEffectiveFaultInjectionRule(FaultInjectionRule rule, IFaultInjectionRuleInternal ruleInternal);
5354
}
5455
}
56+
57+
public static final class FaultInjectionConditionHelper {
58+
private static final AtomicBoolean faultInjectionConditionClassLoaded = new AtomicBoolean(false);
59+
private static final AtomicReference<FaultInjectionConditionAccessor> accessor = new AtomicReference<>();
60+
61+
private FaultInjectionConditionHelper() {
62+
}
63+
64+
public static FaultInjectionConditionAccessor getFaultInjectionConditionAccessor() {
65+
if (!faultInjectionConditionClassLoaded.get()) {
66+
logger.debug("Initializing FaultInjectionConditionAccessor...");
67+
}
68+
69+
FaultInjectionConditionAccessor snapshot = accessor.get();
70+
if (snapshot == null) {
71+
logger.error("FaultInjectionConditionAccessor is not initialized yet!");
72+
System.exit(8701); // Using a unique status code here to help debug the issue.
73+
}
74+
75+
return snapshot;
76+
}
77+
78+
public static void setFaultInjectionConditionAccessor(final FaultInjectionConditionAccessor newAccessor) {
79+
80+
assert (newAccessor != null);
81+
82+
if (!accessor.compareAndSet(null, newAccessor)) {
83+
logger.debug("FaultInjectionConditionAccessor already initialized!");
84+
} else {
85+
logger.debug("Setting FaultInjectionConditionAccessor...");
86+
faultInjectionConditionClassLoaded.set(true);
87+
}
88+
}
89+
90+
public interface FaultInjectionConditionAccessor {
91+
boolean isMetadataOperationType(FaultInjectionCondition faultInjectionCondition);
92+
}
93+
}
5594
}

0 commit comments

Comments
 (0)