@@ -4,6 +4,7 @@ import path from "path";
44import { cleanAllRawLogs , cleanForksLogs } from "@helpers/analyzer" ;
55import "dotenv/config" ;
66import {
7+ chaosPresets ,
78 epochRotationOperations ,
89 groupCount ,
910 installationCount ,
@@ -15,13 +16,16 @@ import {
1516 targetEpoch ,
1617 testName ,
1718 workerNames ,
19+ type ChaosLevel ,
1820} from "./config" ;
1921
2022interface ForkOptions {
2123 count : number ; // Number of times to run the process (default: 100)
2224 cleanAll : boolean ; // Clean all raw logs before starting
2325 removeNonMatching : boolean ; // Remove non-matching logs
2426 env ?: string ; // XMTP environment (local, dev, production)
27+ chaosEnabled : boolean ; // Enable network chaos
28+ chaosLevel : ChaosLevel ; // Chaos level (low, medium, high)
2529}
2630
2731function showHelp ( ) {
@@ -37,13 +41,22 @@ OPTIONS:
3741 --remove-non-matching Remove logs that don't contain fork content [default: true]
3842 --no-remove-non-matching Keep logs that don't contain fork content
3943 --env <environment> XMTP environment (local, dev, production) [default: dev]
44+ --chaos-enabled Enable network chaos testing (requires --env local)
45+ --chaos-level <level> Chaos level: low, medium, high [default: medium]
4046 -h, --help Show this help message
4147
48+ CHAOS LEVELS:
49+ low - Delay: 50-150ms, Jitter: 0-50ms, Loss: 0-2%, Interval: 15s
50+ medium - Delay: 100-300ms, Jitter: 0-75ms, Loss: 0-3.5%, Interval: 10s
51+ high - Delay: 100-500ms, Jitter: 0-100ms, Loss: 0-5%, Interval: 10s
52+
4253EXAMPLES:
43- yarn fork # Run 100 times and get stats
44- yarn fork --count 50 # Run 50 times
45- yarn fork --clean-all # Clean all raw logs before starting
46- yarn fork --count 200 --env local # Run 200 times on local environment
54+ yarn fork # Run 100 times and get stats
55+ yarn fork --count 50 # Run 50 times
56+ yarn fork --clean-all # Clean all raw logs before starting
57+ yarn fork --count 200 --env local # Run 200 times on local environment
58+ yarn fork --env local --chaos-enabled # Run with medium network chaos
59+ yarn fork --env local --chaos-enabled --chaos-level high # Run with high chaos
4760
4861For more information, see: forks/README.md
4962` ) ;
@@ -63,16 +76,21 @@ function getForkCount(): number {
6376/**
6477 * Run the fork test (suppress output)
6578 */
66- function runForkTest ( env ?: string ) : void {
67- const envFlag = env ? `--env ${ env } ` : "" ;
79+ function runForkTest ( options : ForkOptions ) : void {
80+ const envFlag = options . env ? `--env ${ options . env } ` : "" ;
6881 const command = `yarn test forks ${ envFlag } --log warn --file` . trim ( ) ;
6982
7083 try {
7184 execSync ( command , {
7285 stdio : "ignore" ,
73- env : { ...process . env } ,
86+ env : {
87+ ...process . env ,
88+ CHAOS_ENABLED : options . chaosEnabled ? "true" : "false" ,
89+ CHAOS_LEVEL : options . chaosLevel ,
90+ } ,
7491 } ) ;
7592 } catch {
93+ console . log ( "Error running fork test" ) ;
7694 // Test may fail if forks are detected, that's expected
7795 // We'll analyze the logs afterward
7896 }
@@ -81,7 +99,7 @@ function runForkTest(env?: string): void {
8199/**
82100 * Log fork matrix parameters from shared config
83101 */
84- function logForkMatrixParameters ( ) : void {
102+ function logForkMatrixParameters ( options : ForkOptions ) : void {
85103 console . info ( "\nFORK MATRIX PARAMETERS" ) ;
86104 console . info ( "-" . repeat ( 60 ) ) ;
87105 console . info ( `groupCount: ${ groupCount } ` ) ;
@@ -97,6 +115,18 @@ function logForkMatrixParameters(): void {
97115 console . info ( `randomInboxIdsCount: ${ randomInboxIdsCount } ` ) ;
98116 console . info ( `installationCount: ${ installationCount } ` ) ;
99117 console . info ( `testName: ${ testName } ` ) ;
118+
119+ if ( options . chaosEnabled ) {
120+ const preset = chaosPresets [ options . chaosLevel ] ;
121+ console . info ( "\nNETWORK CHAOS PARAMETERS" ) ;
122+ console . info ( `chaosEnabled: true` ) ;
123+ console . info ( `chaosLevel: ${ options . chaosLevel } ` ) ;
124+ console . info ( ` delay: ${ preset . delayMin } -${ preset . delayMax } ms` ) ;
125+ console . info ( ` jitter: ${ preset . jitterMin } -${ preset . jitterMax } ms` ) ;
126+ console . info ( ` packetLoss: ${ preset . lossMin } -${ preset . lossMax } %` ) ;
127+ console . info ( ` interval: ${ preset . interval } ms` ) ;
128+ }
129+
100130 console . info ( "-" . repeat ( 60 ) + "\n" ) ;
101131}
102132
@@ -108,8 +138,17 @@ async function runForkDetection(options: ForkOptions): Promise<void> {
108138 console . info ( "XMTP Fork Detection CLI" ) ;
109139 console . info ( "=" . repeat ( 60 ) ) ;
110140
141+ // Validate chaos requirements
142+ if ( options . chaosEnabled && options . env !== "local" ) {
143+ console . error ( "\n❌ Error: Network chaos testing requires --env local" ) ;
144+ console . error (
145+ "Network chaos manipulates Docker containers which are only available in local environment.\n" ,
146+ ) ;
147+ process . exit ( 1 ) ;
148+ }
149+
111150 // Log fork matrix parameters once
112- logForkMatrixParameters ( ) ;
151+ logForkMatrixParameters ( options ) ;
113152
114153 console . info ( `Running fork detection process ${ options . count } time(s)...\n` ) ;
115154
@@ -130,7 +169,7 @@ async function runForkDetection(options: ForkOptions): Promise<void> {
130169 // Run the test N times
131170 for ( let i = 1 ; i <= options . count ; i ++ ) {
132171 // Run the fork test (silently)
133- runForkTest ( options . env ) ;
172+ runForkTest ( options ) ;
134173
135174 // Clean and analyze fork logs after the test (suppress output)
136175 const originalConsoleDebug = console . debug ;
@@ -211,6 +250,8 @@ async function main() {
211250 cleanAll : false ,
212251 removeNonMatching : true ,
213252 env : process . env . XMTP_ENV || "dev" ,
253+ chaosEnabled : false ,
254+ chaosLevel : "medium" ,
214255 } ;
215256
216257 // Parse arguments
@@ -260,6 +301,25 @@ async function main() {
260301 process . exit ( 1 ) ;
261302 }
262303 break ;
304+ case "--chaos-enabled" :
305+ options . chaosEnabled = true ;
306+ break ;
307+ case "--chaos-level" :
308+ if ( i + 1 < args . length ) {
309+ const level = args [ i + 1 ] as ChaosLevel ;
310+ if ( ! [ "low" , "medium" , "high" ] . includes ( level ) ) {
311+ console . error ( "--chaos-level must be one of: low, medium, high" ) ;
312+ process . exit ( 1 ) ;
313+ }
314+ options . chaosLevel = level ;
315+ i ++ ; // Skip next argument
316+ } else {
317+ console . error (
318+ "--chaos-level flag requires a value (e.g., --chaos-level medium)" ,
319+ ) ;
320+ process . exit ( 1 ) ;
321+ }
322+ break ;
263323 default :
264324 console . error ( `Unknown option: ${ arg } ` ) ;
265325 console . error ( "Use --help for usage information" ) ;
0 commit comments