Skip to content

Commit 7f3c59b

Browse files
Cae 633 add functional tests notifications (#3357)
* DOC-4758 async JSON doc examples (#3335) * DOC-4758 added landing page examples * DOC-4758 added Path page examples * DOC-4758 work around arrAppend issue * DOC-4758 applied formatting * WIP: staging changes before rebase to lettuce-observability * Fix MOVING push notification capture using PushListener API - Fixed receiveMovingPushNotificationTest to properly capture MOVING messages - Switched from flawed ping-based approach to proper PushListener API - Added ByteBuffer decoding to extract actual IP addresses from push messages - Enhanced two-step rebind process (migrate + bind) working correctly - Successfully capturing RESP3 push messages: MOVING, MIGRATING, MIGRATED, etc. - Test now passes and captures real MOVING notifications during endpoint rebind The test now properly hooks into Lettuce's protocol layer to capture RESP3 push messages that come before command responses, solving the core issue where we were only seeing PONG responses. * CAE-633: Fix Redis Enterprise cluster configuration discovery and push notification tests - Fixed stale cluster configuration issue in RedisEnterpriseConfigDiscovery - Added proper cache clearing in parseShards() method to get fresh master/slave lists - Added getNodeWithMasterShards() method for proper node selection in failover tests - Fixed infinite retry loops in FaultInjectionClient validation - Updated MaintenanceNotificationTest to use dynamic node selection for both FAILING_OVER and FAILED_OVER tests - Added CONTEXT_MOVING_PUSH_NOTIFICATIONS.md to .gitignore - All push notification tests now working with real-time dynamic cluster discovery * Fix critical bugs in push notification tests - all tests now passing - Fix double-prefixing bug in shard ID state recording * originalShardRoles.put(masterShard, 'master') instead of 'redis:' + masterShard * Prevents malformed redis:redis:1 IDs that broke state restoration - Increase migration timeout from 120s to 300s in FaultInjectionClient * Migration operations move actual data and need more time than failovers * Fixes receiveMigratedPushNotificationTest timeout failures - Fix cluster state restoration logic to only failover master shards * Redis Enterprise constraint: only master shards can be failed over * Prevents 'ERROR: No such master shard id' when trying to failover slaves * Only targets current masters that should become slaves - Complete test suite now passing: 5/5 tests successful * MOVING, MIGRATING, MIGRATED, FAILING_OVER, FAILED_OVER notifications * Dynamic cluster discovery with proper state isolation * Real-time adaptation to cluster state changes between test runs Tests run: 5, Failures: 0, Errors: 0, Skipped: 0 * refactor: Clean up scenario folder - remove legacy methods and magic numbers - Remove all legacy methods with hardcoded defaults from FaultInjectionClient: * triggerShardMigration(String, String) - 2-parameter version * triggerShardFailover(String, String) - 2-parameter version * triggerShardFailover(String, String, String) - 3-parameter version * triggerMovingNotification(String, String, String) - 3-parameter version * validateRladminCommandCompletion() - useless method - Replace magic numbers with meaningful constants across scenario folder: * Use Duration.ofMinutes() for long timeouts (300s->5min, 180s->3min, etc.) * Add descriptive constants for all timeout values * Improve code readability and maintainability - Update tests to use 4-parameter dynamic discovery methods - Fix Jackson import to use proper import instead of full package name - Update maintenance operation system to handle missing legacy methods All tests pass and compilation successful. * Fix StepVerifier timeout issues and remove .vscode/settings.json from tracking - Increase StepVerifier timeout for long-running operations (migrations/failovers) - Change from .verifyComplete() to .expectComplete().verify(LONG_OPERATION_TIMEOUT) - All tests now complete successfully without timing out - Remove .vscode/settings.json from git tracking --------- Co-authored-by: andy-stark-redis <[email protected]>
1 parent 6e59610 commit 7f3c59b

File tree

6 files changed

+3037
-5
lines changed

6 files changed

+3037
-5
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ dependency-reduced-pom.xml
1616
.idea
1717
.flattened-pom.xml
1818
*.java-version
19-
*.DS_Store
19+
*.DS_Store
20+
.vscode*

src/test/java/io/lettuce/scenario/FaultInjectionClient.java

Lines changed: 603 additions & 4 deletions
Large diffs are not rendered by default.
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
package io.lettuce.scenario;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
5+
import java.util.Arrays;
6+
7+
import org.junit.jupiter.api.DisplayName;
8+
import org.junit.jupiter.api.Tag;
9+
import org.junit.jupiter.api.Test;
10+
11+
import io.lettuce.scenario.FaultInjectionClient.MaintenanceOperation;
12+
import io.lettuce.scenario.FaultInjectionClient.MaintenanceOperationType;
13+
import reactor.test.StepVerifier;
14+
15+
import static io.lettuce.TestTags.UNIT_TEST;
16+
17+
/**
18+
* Unit tests for FaultInjectionClient to verify compilation and basic functionality.
19+
*/
20+
@Tag(UNIT_TEST)
21+
public class FaultInjectionClientUnitTest {
22+
23+
@Test
24+
@DisplayName("FaultInjectionClient can be instantiated")
25+
public void canInstantiateFaultInjectionClient() {
26+
FaultInjectionClient client = new FaultInjectionClient();
27+
assertThat(client).isNotNull();
28+
}
29+
30+
@Test
31+
@DisplayName("executeRladminCommand validates parameters")
32+
public void executeRladminCommandValidatesParameters() {
33+
FaultInjectionClient client = new FaultInjectionClient();
34+
35+
// Test null BDB ID
36+
StepVerifier.create(client.executeRladminCommand(null, "test command")).expectError(IllegalArgumentException.class)
37+
.verify();
38+
39+
// Test empty BDB ID
40+
StepVerifier.create(client.executeRladminCommand("", "test command")).expectError(IllegalArgumentException.class)
41+
.verify();
42+
43+
// Test null command
44+
StepVerifier.create(client.executeRladminCommand("123", null)).expectError(IllegalArgumentException.class).verify();
45+
46+
// Test empty command
47+
StepVerifier.create(client.executeRladminCommand("123", "")).expectError(IllegalArgumentException.class).verify();
48+
}
49+
50+
@Test
51+
@DisplayName("triggerEndpointRebind validates parameters")
52+
public void triggerEndpointRebindValidatesParameters() {
53+
FaultInjectionClient client = new FaultInjectionClient();
54+
55+
// Test null endpoint ID
56+
StepVerifier.create(client.triggerEndpointRebind("123", null, "single")).expectError(IllegalArgumentException.class)
57+
.verify();
58+
59+
// Test null policy
60+
StepVerifier.create(client.triggerEndpointRebind("123", "1", null)).expectError(IllegalArgumentException.class)
61+
.verify();
62+
}
63+
64+
@Test
65+
@DisplayName("triggerShardMigration validates shard ID format")
66+
public void triggerShardMigrationValidatesShardId() {
67+
FaultInjectionClient client = new FaultInjectionClient();
68+
69+
// Test invalid shard ID format using 4-parameter version
70+
StepVerifier.create(client.triggerShardMigration("123", "invalid", "1", "2"))
71+
.expectError(IllegalArgumentException.class).verify();
72+
}
73+
74+
@Test
75+
@DisplayName("triggerShardFailover validates parameters")
76+
public void triggerShardFailoverValidatesParameters() {
77+
FaultInjectionClient client = new FaultInjectionClient();
78+
79+
// Test null RedisEnterpriseConfig
80+
StepVerifier.create(client.triggerShardFailover("123", "1", "1", null)).expectError(IllegalArgumentException.class)
81+
.verify();
82+
83+
// Test null nodeId
84+
StepVerifier.create(client.triggerShardFailover("123", "1", null, new RedisEnterpriseConfig("123")))
85+
.expectError(IllegalArgumentException.class).verify();
86+
}
87+
88+
@Test
89+
@DisplayName("MaintenanceOperation can be created for endpoint rebind")
90+
public void canCreateMaintenanceOperationForEndpointRebind() {
91+
MaintenanceOperation operation = new MaintenanceOperation(MaintenanceOperationType.ENDPOINT_REBIND, "1", "single");
92+
93+
assertThat(operation.getType()).isEqualTo(MaintenanceOperationType.ENDPOINT_REBIND);
94+
assertThat(operation.getEndpointId()).isEqualTo("1");
95+
assertThat(operation.getPolicy()).isEqualTo("single");
96+
assertThat(operation.getShardId()).isNull();
97+
}
98+
99+
@Test
100+
@DisplayName("MaintenanceOperation can be created for shard migration")
101+
public void canCreateMaintenanceOperationForShardMigration() {
102+
MaintenanceOperation operation = new MaintenanceOperation(MaintenanceOperationType.SHARD_MIGRATION, "1");
103+
104+
assertThat(operation.getType()).isEqualTo(MaintenanceOperationType.SHARD_MIGRATION);
105+
assertThat(operation.getShardId()).isEqualTo("1");
106+
assertThat(operation.getEndpointId()).isNull();
107+
assertThat(operation.getPolicy()).isNull();
108+
}
109+
110+
@Test
111+
@DisplayName("MaintenanceOperation can be created for shard failover")
112+
public void canCreateMaintenanceOperationForShardFailover() {
113+
MaintenanceOperation operation = new MaintenanceOperation(MaintenanceOperationType.SHARD_FAILOVER, "2");
114+
115+
assertThat(operation.getType()).isEqualTo(MaintenanceOperationType.SHARD_FAILOVER);
116+
assertThat(operation.getShardId()).isEqualTo("2");
117+
assertThat(operation.getEndpointId()).isNull();
118+
assertThat(operation.getPolicy()).isNull();
119+
}
120+
121+
@Test
122+
@DisplayName("triggerMaintenanceSequence validates parameters")
123+
public void triggerMaintenanceSequenceValidatesParameters() {
124+
FaultInjectionClient client = new FaultInjectionClient();
125+
126+
// Test null operations
127+
StepVerifier.create(client.triggerMaintenanceSequence("123", null)).expectError(IllegalArgumentException.class)
128+
.verify();
129+
130+
// Test empty operations
131+
StepVerifier.create(client.triggerMaintenanceSequence("123", Arrays.asList()))
132+
.expectError(IllegalArgumentException.class).verify();
133+
}
134+
135+
@Test
136+
@DisplayName("MaintenanceOperation toString produces readable output")
137+
public void maintenanceOperationToStringIsReadable() {
138+
MaintenanceOperation rebindOp = new MaintenanceOperation(MaintenanceOperationType.ENDPOINT_REBIND, "1", "single");
139+
MaintenanceOperation migrateOp = new MaintenanceOperation(MaintenanceOperationType.SHARD_MIGRATION, "1");
140+
MaintenanceOperation failoverOp = new MaintenanceOperation(MaintenanceOperationType.SHARD_FAILOVER, "2");
141+
142+
assertThat(rebindOp.toString()).contains("EndpointRebind");
143+
assertThat(rebindOp.toString()).contains("endpoint=1");
144+
assertThat(rebindOp.toString()).contains("policy=single");
145+
146+
assertThat(migrateOp.toString()).contains("ShardMigration");
147+
assertThat(migrateOp.toString()).contains("shard=1");
148+
149+
assertThat(failoverOp.toString()).contains("ShardFailover");
150+
assertThat(failoverOp.toString()).contains("shard=2");
151+
}
152+
153+
}

0 commit comments

Comments
 (0)