@@ -2,8 +2,9 @@ import { getTime } from "@helpers/logger";
22import { type Group } from "@helpers/versions" ;
33import { setupDurationTracking } from "@helpers/vitest" ;
44import { getInboxes } from "@inboxes/utils" ;
5+ import { typeofStream } from "@workers/main" ;
56import { getWorkers , type Worker } from "@workers/manager" ;
6- import { describe , it } from "vitest" ;
7+ import { describe , expect , it } from "vitest" ;
78import { DockerContainer } from "../network-stability/container" ;
89import {
910 chaosConfig ,
@@ -17,71 +18,17 @@ import {
1718 otherOperations ,
1819 parallelOperations ,
1920 randomInboxIdsCount ,
21+ streamsEnabled ,
2022 targetEpoch ,
2123 testName ,
2224 workerNames ,
23- type ChaosPreset ,
2425} from "./config" ;
25-
26- const startChaos = (
27- allNodes : DockerContainer [ ] ,
28- preset : ChaosPreset ,
29- ) : NodeJS . Timeout => {
30- console . log ( `[chaos] Initialized ${ allNodes . length } Docker containers` ) ;
31-
32- // Validate containers are running
33- for ( const node of allNodes ) {
34- try {
35- // Test if container exists by trying to get its IP
36- if ( ! node . ip ) {
37- throw new Error ( `Container ${ node . name } has no IP address` ) ;
38- }
39- } catch {
40- throw new Error (
41- `Docker container ${ node . name } is not running. Network chaos requires local multinode setup (./dev/up).` ,
42- ) ;
43- }
44- }
45- console . log ( "[chaos] All Docker containers validated" ) ;
46-
47- // Function to apply chaos to all nodes
48- const applyChaos = ( ) => {
49- console . log (
50- "[chaos] Applying jitter, delay, and drop rules to all nodes..." ,
51- ) ;
52- for ( const node of allNodes ) {
53- const delay = Math . floor (
54- preset . delayMin + Math . random ( ) * ( preset . delayMax - preset . delayMin ) ,
55- ) ;
56- const jitter = Math . floor (
57- preset . jitterMin +
58- Math . random ( ) * ( preset . jitterMax - preset . jitterMin ) ,
59- ) ;
60- const loss =
61- preset . lossMin + Math . random ( ) * ( preset . lossMax - preset . lossMin ) ;
62-
63- try {
64- node . addJitter ( delay , jitter ) ;
65- if ( Math . random ( ) < 0.5 ) node . addLoss ( loss ) ;
66- } catch ( err ) {
67- console . warn ( `[chaos] Error applying netem on ${ node . name } :` , err ) ;
68- }
69- }
70- } ;
71-
72- // Apply chaos immediately
73- applyChaos ( ) ;
74-
75- return setInterval ( applyChaos , preset . interval ) ;
76- } ;
26+ import { clearChaos , startChaos } from "./utils" ;
7727
7828describe ( testName , ( ) => {
7929 setupDurationTracking ( { testName } ) ;
8030
81- const createOperations = async ( worker : Worker , group : Group ) => {
82- // This syncs all and can contribute to the fork
83- await worker . client . conversations . syncAll ( ) ;
84-
31+ const createOperations = ( worker : Worker , group : Group ) => {
8532 // Fetches the group from the worker perspective
8633 const getGroup = ( ) =>
8734 worker . client . conversations . getConversationById (
@@ -121,6 +68,7 @@ describe(testName, () => {
12168 getGroup ( ) . then ( ( g ) =>
12269 g . send ( `Message from ${ worker . name } ` ) . then ( ( ) => { } ) ,
12370 ) ,
71+ sync : ( ) => getGroup ( ) . then ( ( g ) => g . sync ( ) ) ,
12472 } ;
12573 } ;
12674
@@ -129,13 +77,21 @@ describe(testName, () => {
12977 let allNodes : DockerContainer [ ] = [ ] ;
13078 let chaosInterval : NodeJS . Timeout | undefined ;
13179 let verifyInterval : NodeJS . Timeout | undefined ;
80+ let mustFail = false ;
13281
13382 try {
13483 let workers = await getWorkers ( workerNames , {
13584 env : network as "local" | "dev" | "production" ,
13685 nodeBindings : NODE_VERSION ,
13786 } ) ;
138- // Note: typeofStreamForTest and typeOfSyncForTest are set to None, so no streams or syncs to start
87+
88+ // Enable message streams if configured
89+ if ( streamsEnabled ) {
90+ console . log ( "[streams] Enabling message streams on all workers" ) ;
91+ workers . getAll ( ) . forEach ( ( worker ) => {
92+ worker . worker . startStream ( typeofStream . Message ) ;
93+ } ) ;
94+ }
13995
14096 // Initialize network chaos if enabled
14197 if ( chaosConfig . enabled ) {
@@ -159,7 +115,6 @@ describe(testName, () => {
159115 await workers . checkForks ( ) ;
160116 } catch ( e ) {
161117 console . warn ( "[verify] Skipping check due to exception:" , e ) ;
162- throw e ;
163118 }
164119 } ) ( ) ;
165120 } , 10 * 1000 ) ;
@@ -175,6 +130,9 @@ describe(testName, () => {
175130 const group = await workers . createGroupBetweenAll ( ) ;
176131
177132 let currentEpoch = 0n ;
133+ await Promise . all (
134+ workers . getAll ( ) . map ( ( w ) => w . client . conversations . sync ( ) ) ,
135+ ) ;
178136
179137 while ( currentEpoch < targetEpoch ) {
180138 const parallelOperationsArray = Array . from (
@@ -186,7 +144,7 @@ describe(testName, () => {
186144 Math . floor ( Math . random ( ) * workers . getAll ( ) . length )
187145 ] ;
188146
189- const ops = await createOperations ( randomWorker , group ) ;
147+ const ops = createOperations ( randomWorker , group ) ;
190148 const operationList = [
191149 ...( epochRotationOperations . updateName
192150 ? [ ops . updateName ]
@@ -203,6 +161,7 @@ describe(testName, () => {
203161 ? [ ops . createInstallation ]
204162 : [ ] ) ,
205163 ...( otherOperations . sendMessage ? [ ops . sendMessage ] : [ ] ) ,
164+ ...( otherOperations . sync ? [ ops . sync ] : [ ] ) ,
206165 ] ;
207166
208167 const randomOperation =
@@ -217,11 +176,19 @@ describe(testName, () => {
217176 await randomOperation ( ) ;
218177 await otherRandomOperation ( ) ;
219178 } catch ( e ) {
220- console . log ( `Group ${ groupIndex + 1 } operation failed:` , e ) ;
179+ console . error (
180+ `Group ${ groupIndex + 1 } operation failed:` ,
181+ e ,
182+ ) ;
221183 }
222184 } ) ( ) ,
223185 ) ;
224- await Promise . all ( parallelOperationsArray ) ;
186+ try {
187+ await Promise . all ( parallelOperationsArray ) ;
188+ } catch ( e ) {
189+ console . error ( `Group ${ groupIndex + 1 } operation failed:` , e ) ;
190+ }
191+
225192 await workers . checkForksForGroup ( group . id ) ;
226193 currentEpoch = ( await group . debugInfo ( ) ) . epoch ;
227194 }
@@ -232,35 +199,29 @@ describe(testName, () => {
232199
233200 await Promise . all ( groupOperationPromises ) ;
234201 await workers . checkForks ( ) ;
235- } catch ( e ) {
202+ } catch ( e : any ) {
236203 console . error ( "Error during fork testing:" , e ) ;
204+ mustFail = true ;
237205 } finally {
238206 if ( verifyInterval ) {
239207 clearInterval ( verifyInterval ) ;
240208 }
241209 // Clean up chaos if it was enabled
242210 if ( chaosConfig . enabled ) {
243211 console . log ( "[chaos] Cleaning up network chaos..." ) ;
244-
245212 // Clear intervals
246213 if ( chaosInterval ) {
247214 clearInterval ( chaosInterval ) ;
248215 }
249216
250- // Clear network rules
251- for ( const node of allNodes ) {
252- try {
253- node . clearLatency ( ) ;
254- } catch ( err ) {
255- console . warn (
256- `[chaos] Error clearing latency on ${ node . name } :` ,
257- err ,
258- ) ;
259- }
260- }
217+ clearChaos ( allNodes ) ;
261218
262219 console . log ( "[chaos] Cleanup complete" ) ;
263220 }
221+
222+ if ( mustFail ) {
223+ expect . fail ( `Test failed` ) ;
224+ }
264225 }
265226 } ) ;
266227} ) ;
0 commit comments