1
1
import assert from "node:assert" ;
2
- import { setTimeout } from "node:timers/promises" ;
2
+
3
3
import { FaultInjectorClient } from "./fault-injector-client" ;
4
4
import {
5
+ ClientFactory ,
5
6
getDatabaseConfig ,
6
7
getDatabaseConfigFromEnv ,
7
8
getEnvConfig ,
8
9
RedisConnectionConfig ,
10
+ blockSetImmediate
9
11
} from "./test-scenario.util" ;
10
12
import { createClient } from "../../.." ;
11
13
import { before } from "mocha" ;
12
14
import { TestCommandRunner } from "./test-command-runner" ;
13
15
14
16
describe ( "Timeout Handling During Notifications" , ( ) => {
15
17
let clientConfig : RedisConnectionConfig ;
16
- let client : ReturnType < typeof createClient < any , any , any , 3 > > ;
18
+ let clientFactory : ClientFactory ;
17
19
let faultInjectorClient : FaultInjectorClient ;
18
- let commandRunner : TestCommandRunner ;
20
+ let defaultClient : ReturnType < typeof createClient < any , any , any , any > > ;
19
21
20
22
before ( ( ) => {
21
23
const envConfig = getEnvConfig ( ) ;
22
24
const redisConfig = getDatabaseConfigFromEnv (
23
25
envConfig . redisEndpointsConfigPath
24
26
) ;
25
27
26
- faultInjectorClient = new FaultInjectorClient ( envConfig . faultInjectorUrl ) ;
27
28
clientConfig = getDatabaseConfig ( redisConfig ) ;
29
+ faultInjectorClient = new FaultInjectorClient ( envConfig . faultInjectorUrl ) ;
30
+ clientFactory = new ClientFactory ( clientConfig ) ;
28
31
} ) ;
29
32
30
33
beforeEach ( async ( ) => {
31
- client = createClient ( {
32
- socket : {
33
- host : clientConfig . host ,
34
- port : clientConfig . port ,
35
- ...( clientConfig . tls === true ? { tls : true } : { } ) ,
36
- } ,
37
- password : clientConfig . password ,
38
- username : clientConfig . username ,
39
- RESP : 3 ,
40
- maintPushNotifications : "auto" ,
41
- maintMovingEndpointType : "auto" ,
42
- } ) ;
43
-
44
- client . on ( "error" , ( err : Error ) => {
45
- throw new Error ( `Client error: ${ err . message } ` ) ;
46
- } ) ;
47
-
48
- commandRunner = new TestCommandRunner ( client ) ;
34
+ defaultClient = await clientFactory . create ( "default" ) ;
49
35
50
- await client . connect ( ) ;
36
+ await defaultClient . flushAll ( ) ;
51
37
} ) ;
52
38
53
- afterEach ( ( ) => {
54
- client . destroy ( ) ;
39
+ afterEach ( async ( ) => {
40
+ clientFactory . destroyAll ( ) ;
55
41
} ) ;
56
42
57
43
it ( "should relax command timeout on MOVING, MIGRATING, and MIGRATED" , async ( ) => {
58
44
// PART 1
59
45
// Set very low timeout to trigger errors
60
- client . options ! . maintRelaxedCommandTimeout = 50 ;
46
+ const lowTimeoutClient = await clientFactory . create ( "lowTimeout" , {
47
+ maintRelaxedCommandTimeout : 50 ,
48
+ } ) ;
61
49
62
50
const { action_id : lowTimeoutBindAndMigrateActionId } =
63
51
await faultInjectorClient . migrateAndBindAction ( {
@@ -70,7 +58,10 @@ describe("Timeout Handling During Notifications", () => {
70
58
) ;
71
59
72
60
const lowTimeoutCommandPromises =
73
- await commandRunner . fireCommandsUntilStopSignal ( lowTimeoutWaitPromise ) ;
61
+ await TestCommandRunner . fireCommandsUntilStopSignal (
62
+ lowTimeoutClient ,
63
+ lowTimeoutWaitPromise
64
+ ) ;
74
65
75
66
const lowTimeoutRejectedCommands = (
76
67
await Promise . all ( lowTimeoutCommandPromises . commandPromises )
@@ -90,7 +81,9 @@ describe("Timeout Handling During Notifications", () => {
90
81
91
82
// PART 2
92
83
// Set high timeout to avoid errors
93
- client . options ! . maintRelaxedCommandTimeout = 10000 ;
84
+ const highTimeoutClient = await clientFactory . create ( "highTimeout" , {
85
+ maintRelaxedCommandTimeout : 10000 ,
86
+ } ) ;
94
87
95
88
const { action_id : highTimeoutBindAndMigrateActionId } =
96
89
await faultInjectorClient . migrateAndBindAction ( {
@@ -103,7 +96,10 @@ describe("Timeout Handling During Notifications", () => {
103
96
) ;
104
97
105
98
const highTimeoutCommandPromises =
106
- await commandRunner . fireCommandsUntilStopSignal ( highTimeoutWaitPromise ) ;
99
+ await TestCommandRunner . fireCommandsUntilStopSignal (
100
+ highTimeoutClient ,
101
+ highTimeoutWaitPromise
102
+ ) ;
107
103
108
104
const highTimeoutRejectedCommands = (
109
105
await Promise . all ( highTimeoutCommandPromises . commandPromises )
@@ -112,13 +108,15 @@ describe("Timeout Handling During Notifications", () => {
112
108
assert . strictEqual ( highTimeoutRejectedCommands . length , 0 ) ;
113
109
} ) ;
114
110
115
- // TODO this is WIP
116
- it . skip ( "should unrelax command timeout after MAINTENANCE" , async ( ) => {
117
- client . options ! . maintRelaxedCommandTimeout = 10000 ;
118
- client . options ! . commandOptions = {
119
- ...client . options ! . commandOptions ,
120
- timeout : 1 , // Set very low timeout to trigger errors
121
- } ;
111
+ it ( "should unrelax command timeout after MAINTENANCE" , async ( ) => {
112
+ const clientWithCommandTimeout = await clientFactory . create (
113
+ "clientWithCommandTimeout" ,
114
+ {
115
+ commandOptions : {
116
+ timeout : 100 ,
117
+ } ,
118
+ }
119
+ ) ;
122
120
123
121
const { action_id : bindAndMigrateActionId } =
124
122
await faultInjectorClient . migrateAndBindAction ( {
@@ -131,25 +129,31 @@ describe("Timeout Handling During Notifications", () => {
131
129
) ;
132
130
133
131
const relaxedTimeoutCommandPromises =
134
- await commandRunner . fireCommandsUntilStopSignal ( lowTimeoutWaitPromise ) ;
132
+ await TestCommandRunner . fireCommandsUntilStopSignal (
133
+ clientWithCommandTimeout ,
134
+ lowTimeoutWaitPromise
135
+ ) ;
135
136
136
137
const relaxedTimeoutRejectedCommands = (
137
138
await Promise . all ( relaxedTimeoutCommandPromises . commandPromises )
138
139
) . filter ( ( result ) => result . status === "rejected" ) ;
139
- console . log (
140
- "relaxedTimeoutRejectedCommands" ,
141
- relaxedTimeoutRejectedCommands
142
- ) ;
143
140
144
141
assert . ok ( relaxedTimeoutRejectedCommands . length === 0 ) ;
145
142
146
- const unrelaxedCommandPromises =
147
- await commandRunner . fireCommandsUntilStopSignal ( setTimeout ( 1 * 1000 ) ) ;
143
+ const start = performance . now ( ) ;
148
144
149
- const unrelaxedRejectedCommands = (
150
- await Promise . all ( unrelaxedCommandPromises . commandPromises )
151
- ) . filter ( ( result ) => result . status === "rejected" ) ;
145
+ let error : any ;
146
+ await blockSetImmediate ( async ( ) => {
147
+ try {
148
+ await clientWithCommandTimeout . set ( "key" , "value" ) ;
149
+ } catch ( err : any ) {
150
+ error = err ;
151
+ }
152
+ } ) ;
152
153
153
- assert . ok ( unrelaxedRejectedCommands . length > 0 ) ;
154
+ // Make sure it took less than 1sec to fail
155
+ assert . ok ( performance . now ( ) - start < 1000 ) ;
156
+ assert . ok ( error instanceof Error ) ;
157
+ assert . ok ( error . constructor . name === "TimeoutError" ) ;
154
158
} ) ;
155
159
} ) ;
0 commit comments